移动辅助类App编程项目
文章目录
基础:掌握Android编程,java程序设计,嵌入式开发
- Android编程:学会简单的UI编程,能够设计XML静态界面布局以及动态更新界面,
熟悉Android四大组件Activity、Service、Broadcast、ContentProvider以及intent消息意图,实现组件之间的通信 - java程序设计:面向对象编程,多线程机制,文件字节字符流输入输出流读写文件,接口与多态
开发软件:Android studio x64
软件说明
本软件设计的目的是防止用户沉迷于耳机。首先设定一个提示时间(建议不超过60分钟), 然后点击开启服务,当佩戴耳机达到预定上限时会自动连续播放一段音频以提示用户。拔下耳机,音频外放一次自动关闭,可以选择清零或者设置更长的限制时间关闭提示。为正常使用软件需获取自启动权限,为避免频繁刷新而删除任务,需要使软件锁定在后台。如果用户不需要使用,可以选择卸载或者关闭自启动功能
实现功能
- 判断耳机断开与连接(蓝牙耳机或有线耳机)
- AlarmService实现定时操作
- 软件服务常驻后台
- 音效均衡器处理单个音频
源代码
layout_main.xml
静态界面布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="example.com.save.MainActivity"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginRight="100sp"
android:layout_marginEnd="100sp">
<TextView
android:textSize="18sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="今日佩戴耳机时长:"/>
<TextView
android:textSize="20sp"
android:text="暂无数据"
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20sp">
<EditText
android:inputType="number"
android:id="@+id/ettv_limit"
android:hint="请输入提示时间(分钟)"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button
android:layout_marginTop="20sp"
android:layout_below="@+id/ettv_limit"
android:id="@+id/bt_ok"
android:text="设定限制时间"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="50sp">
<Button
android:id="@+id/bt_clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="清零"
android:onClick="onClick"/>
<Button
android:id="@+id/bt_read"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="帮助"
android:onClick="onClick"/>
</LinearLayout>
<Button
android:id="@+id/bt_start"
android:layout_marginTop="100sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="开启计时服务"
android:onClick="onClick"/>
<Button
android:id="@+id/bt_get"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="获取自启动权限"
android:onClick="onClick"/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/bt_sound"
android:text="声音处理"
android:onClick="onClick"/>
</LinearLayout>
MainActivity
主界面
package example.com.save;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.SystemClock;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.util.Calendar;
public class MainActivity extends AppCompatActivity{
private EditText set_time;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
}
//点击事件监听
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public void onClick(View view){
int id=view.getId();
switch (id){
case R.id.bt_ok:
if(set_time.getText().toString().equals("")){
Toast.makeText(this,"请输入整数",Toast.LENGTH_SHORT).show();
}else{
int limit=Integer.valueOf(set_time.getText().toString());
FileProcess.writeInternalData(this,"limit.txt",limit*60);
Toast.makeText(this,"已设定提示时间为"+set_time.getText().toString()+"分钟",Toast.LENGTH_LONG).show();
}
break;
case R.id.bt_start:
Intent intent1=new Intent(this,RecordTimeService.class);
intent1.setAction("android.intent.action.Service_TimeRecord");
startService(intent1);
break;
case R.id.bt_clear:
FileProcess.writeInternalData(this,"time.txt",0);
FileProcess.writeInternalData(this,"time2.txt",0);
int time2=(int)(SystemClock.elapsedRealtime()/1000);
FileProcess.writeInternalData(this,"lasttime.txt",time2);
Toast.makeText(this,"已清空计时数据",Toast.LENGTH_SHORT).show();
break;
case R.id.bt_read:
Toast.makeText(this,"使用前需获取自启动权限,然后点击开启服务",Toast.LENGTH_LONG).show();
break;
case R.id.bt_get:
Intent intent=getAutostartSettingIntent(this);
startActivity(intent);
break;
case R.id.bt_sound:
MainActivity.this.startActivity(new Intent(MainActivity.this,SoundActivity.class));
break;
default:
break;
}
}
/**
* 初始化界面
*/
public void init(){
setContentView(R.layout.activity_main);
set_time=(EditText)findViewById(R.id.ettv_limit);
//开启线程每隔两秒更新一次UI数据
final TextView tv_time=(TextView)findViewById(R.id.tv_time);
Handler mTimeHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == 0) {
int n=FileProcess.readInternalData(getApplicationContext(),"time.txt")+FileProcess.readInternalData(getApplicationContext(),"time2.txt");
String min=Integer.toString(n/60);
String sec=Integer.toString(n%60);
tv_time.setText(min+"分"+sec+"秒");
sendEmptyMessageDelayed(0, 2000);
}
}
};
mTimeHandler.sendEmptyMessageDelayed(0, 2000);
}
public static void startbootService(Context context){
Intent intent1=new Intent(context,RecordTimeService.class);
intent1.setAction("android.intent.action.recordtimeservice");
context.startService(intent1);
}
/**
* 获取自启动管理页面的Intent
* 返回自启动管理页面的Intent
* */
public static Intent getAutostartSettingIntent(Context context) {
ComponentName componentName = null;
String brand = Build.MANUFACTURER;
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
switch (brand.toLowerCase()) {
case "samsung"://三星
componentName = new ComponentName("com.samsung.android.sm", "com.samsung.android.sm.app.dashboard.SmartManagerDashBoardActivity");
break;
case "huawei"://华为
//荣耀V8,EMUI 8.0.0,Android 8.0上,以下两者效果一样
componentName = new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity");
// componentName = new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity");//目前看是通用的
break;
case "xiaomi"://小米
componentName = new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity");
break;
case "vivo"://VIVO
// componentName = new ComponentName("com.iqoo.secure", "com.iqoo.secure.safaguard.PurviewTabActivity");
componentName = new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity");
break;
case "oppo"://OPPO
// componentName = new ComponentName("com.oppo.safe", "com.oppo.safe.permission.startup.StartupAppListActivity");
componentName = new ComponentName("com.coloros.oppoguardelf", "com.coloros.powermanager.fuelgaue.PowerUsageModelActivity");
break;
case "yulong":
case "360"://360
componentName = new ComponentName("com.yulong.android.coolsafe", "com.yulong.android.coolsafe.ui.activity.autorun.AutoRunListActivity");
break;
case "meizu"://魅族
componentName = new ComponentName("com.meizu.safe", "com.meizu.safe.permission.SmartBGActivity");
break;
case "oneplus"://一加
componentName = new ComponentName("com.oneplus.security", "com.oneplus.security.chainlaunch.view.ChainLaunchAppListActivity");
break;
case "letv"://乐视
intent.setAction("com.letv.android.permissionautoboot");
default://其他
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", context.getPackageName(), null));
break;
}
intent.setComponent(componentName);
return intent;
}
}
RecordTimeService
服务
package example.com.save;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Toast;
import android.support.annotation.RequiresApi;
public class RecordTimeService extends Service {
// 时钟广播接收器
private static TIME_TICK_Receiver time_tick_receiver;
// 耳机广播接收器
private HeadsetReceiver HeadsetReceiver;
// 长时间计时任务AlarmManager
private AlarmManager manager;
private PendingIntent pi;
// 音频控制
private AudioManager audioManager;
public RecordTimeService() {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public void onCreate(){
super.onCreate();
register_time_receiver();
registerHeadsetReceiver(this);
Intent intent=new Intent(this,MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pd =PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
Notification notify=new Notification.Builder(this)
.setOngoing(true)
.setPriority(Notification.PRIORITY_MAX)
.setContentIntent(pd)
.setContentTitle("监测中")
.setContentText("亲,注意佩戴耳机时长呦")
.setSmallIcon(R.drawable.headplug)
.build();
startForeground(1,notify);
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public int onStartCommand(Intent intent, int flags, int startId){
//Log.i("service", "启动");
manager = (AlarmManager) getSystemService(ALARM_SERVICE);
int three_sec = 3 * 1000;
long triggerAtTime = SystemClock.elapsedRealtime() + three_sec;
Intent i = new Intent(this, AlarmReceiver.class);
pi = PendingIntent.getBroadcast(this, 0, i, 0);
manager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
//aaa.txt中为1则耳机连接,为0则耳机断开
if (FileProcess.readInternalData(getApplicationContext(), "aaa.txt") == 1) {
//这里开辟一条线程,用来执行具体的逻辑操作:
new Thread(new Runnable() {
@Override
public void run() {
//Log.i("Service", "线程");
int time2=(int)(SystemClock.elapsedRealtime()/1000)
- FileProcess.readInternalData(getApplicationContext(),"lasttime.txt");
// 持续佩戴耳机时间
FileProcess.writeInternalData(getApplicationContext(),"time2.txt",time2);
int newTime = FileProcess.readInternalData(getApplicationContext(), "time.txt")
+ FileProcess.readInternalData(getApplicationContext(),"time2.txt");
//判断时长是否超过上限
if (newTime >=FileProcess.readInternalData(getApplicationContext(), "limit.txt") ) {
MediaPlayer mPlayer = MediaPlayer.create(getApplicationContext(),R.raw.red);
//语音提示
try {
if (mPlayer.getCurrentPosition() > 0)
mPlayer.seekTo(0);
mPlayer.start();
// if(!checkIsWired()){
// mPlayer.release();
// }
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
}).start();
}
return super.onStartCommand(intent,flags,startId);
//系统kill服务自动重启
// return Service.START_STICKY;
}
/**
* 注册时钟广播接收器
*/
private void register_time_receiver(){
time_tick_receiver=new TIME_TICK_Receiver();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
registerReceiver(time_tick_receiver, filter);
}
/**
* 注册耳机断开与连接广播接收器
* 判定耳机设备连接状态
*/
public void registerHeadsetReceiver(Service service) {
HeadsetReceiver = new HeadsetReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_HEADSET_PLUG);
service.registerReceiver(HeadsetReceiver, intentFilter);
HeadsetReceiver.setOnHeadsetListener(new OnHeadsetListener() {
@Override
public void isHeadsetConnected(boolean connected) {
if (connected) {
//Log.i("receiver","耳机已连接");
FileProcess.writeInternalData(getApplicationContext(),"aaa.txt",1);
int lasttime=(int)(SystemClock.elapsedRealtime()/1000);
FileProcess.writeInternalData(getApplicationContext(),"lasttime.txt",lasttime);
} else {
//Log.i("receiver","耳机断开");
FileProcess.writeInternalData(getApplicationContext(),"aaa.txt",0);
int newTime=FileProcess.readInternalData(getApplicationContext(),"time.txt")
+ FileProcess.readInternalData(getApplicationContext(),"time2.txt");
FileProcess.writeInternalData(getApplicationContext(), "time.txt", newTime);
FileProcess.writeInternalData(getApplicationContext(),"time2.txt",0);
}
}
});
}
public void onDestroy(){
super.onDestroy();
//Toast.makeText(getApplicationContext(),"onDestroy",Toast.LENGTH_SHORT).show();
//Log.i("service","onDestroy");
}
//判断设备连接的另一种方法
private boolean checkIsWired() {
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
AudioDeviceInfo[] devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
for (AudioDeviceInfo device : devices) {
int deviceType = device.getType();
if (deviceType == AudioDeviceInfo.TYPE_WIRED_HEADSET
|| deviceType == AudioDeviceInfo.TYPE_WIRED_HEADPHONES
|| deviceType == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP
|| deviceType == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) {
return true;
}
}
} else {
return audioManager.isWiredHeadsetOn() || audioManager.isBluetoothScoOn() || audioManager.isBluetoothA2dpOn();
}
return false;
}
}
AlarmReceiver
广播接收器
package example.com.save;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent intent1=new Intent(context,RecordTimeService.class);
intent1.setAction("android.intent.action.recordtimeservice");
context.startService(intent1);
//Log.i("AlarmReceiver","收到");
}
}
FileProcess
静态方法
package example.com.save;
/**
* 内部文件文件读写
*/
import android.content.Context;
import android.icu.util.Calendar;
import android.os.Build;
import android.support.annotation.RequiresApi;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.nio.ByteBuffer;
public class FileProcess {
//写入文件
public static boolean writeInternalData(Context context, String strPath, int intTxt) {
FileOutputStream fos;
try{
fos=context.openFileOutput(strPath,0);
try{
String strTxt=Integer.toString(intTxt);
fos.write(strTxt.getBytes());
return true;
}catch (IOException e){
e.printStackTrace();
return false;
}
}catch (FileNotFoundException e){
e.printStackTrace();
return false;
}
}
//读取文件
public static int readInternalData(Context context, String strPath){
FileInputStream fis ;
byte[] buffer;
try{
fis=context.openFileInput(strPath);
try{
buffer=new byte[fis.available()];
fis.read(buffer);
String file_str=new String(buffer);
int number=Integer.valueOf(file_str);
return number;
}catch (IOException e){
e.printStackTrace();
return 0;
}
}catch (FileNotFoundException e){
e.printStackTrace();
return 0;
}
}
}
OnHeadsetListener
接口(interface)
package example.com.save;
/**
* 耳机断开与连接接口
* true为连接,false为断开
*/
public interface OnHeadsetListener {
void isHeadsetConnected(boolean connected);
}
HeadsetReceiver
耳机广播接收器
package example.com.save;
/**
* 耳机连接状态广播接收器
*/
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class HeadsetReceiver extends BroadcastReceiver {
private OnHeadsetListener onHeadsetListener;
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//蓝牙耳机
if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
int state = adapter.getProfileConnectionState(BluetoothProfile.HEADSET);
if (BluetoothProfile.STATE_CONNECTED == state) {
onHeadsetListener.isHeadsetConnected(true);
}
if (BluetoothProfile.STATE_CONNECTED == state) {
onHeadsetListener.isHeadsetConnected(false);
}
}
//有线耳机
else if (Intent.ACTION_HEADSET_PLUG.equals(action)) {
if (intent.hasExtra("state")) {
int state = intent.getIntExtra("state", 0);
if (state == 1) {
//插入耳机
onHeadsetListener.isHeadsetConnected(true);
} else if (state == 0) {
//拔出耳机
onHeadsetListener.isHeadsetConnected(false);
}
}
}
}
public void setOnHeadsetListener(OnHeadsetListener onHeadsetListener) {
this.onHeadsetListener = onHeadsetListener;
}
}
BootReceiver
开机广播接收器
package example.com.save;
/**
* 开机启动的广播接收器
*/
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//Intent i=new Intent(context,MainActivity.class);
//i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//context.startService(i);
MainActivity.startbootService(context);
}
}
TIME_TICK_Receiver
广播接收器
package example.com.save;
/**
* 开机启动的广播接收器
*/
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//Intent i=new Intent(context,MainActivity.class);
//i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//context.startService(i);
MainActivity.startbootService(context);
}
}
SoundActivity
动态界面
package example.com.save;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.audiofx.BassBoost;
import android.media.audiofx.Equalizer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import java.io.IOException;
public class SoundActivity extends AppCompatActivity {
// 声明音乐文件名
private String music="平凡之路.mp3";
// 文件读取
AssetManager am;
private boolean flag=true;
// 定义播放声音的MediaPlayer
private MediaPlayer mPlayer;
// 定义系统的均衡器
private Equalizer mEqualizer;
// 定义系统的重低音控制器
private BassBoost mBass;
// 定义线性布局
private LinearLayout layout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Log.i("SoundActivity","跳转");
//设置音频流 - STREAM_MUSIC:音乐回放即媒体音量
setVolumeControlStream(AudioManager.STREAM_MUSIC);
layout = new LinearLayout(this);//代码创建布局
layout.setOrientation(LinearLayout.VERTICAL);//设置为线性布局-上下排列
setContentView(layout);//将布局加入到 Activity
//mPlayer = MediaPlayer.create(getApplicationContext(), R.raw.red);
am = this.getAssets();
mPlayer=new MediaPlayer();
prepareMusic(music);
//音乐播放完毕监听器
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
prepareMusic(music);
mPlayer.start();
}
});
// 初始化均衡控制器
setupEqualizer();
// 初始化重低音控制器
setupBassBoost();
// 初始化按钮
setButton();
//mPlayer.start();
}
private void setupEqualizer()
{
// 每个MediaPlayer都有自己独一无二的SessionId
// 以MediaPlayer的AudioSessionId创建Equalizer
// 相当于设置Equalizer负责控制该MediaPlayer
mEqualizer = new Equalizer(0, mPlayer.getAudioSessionId());
// 启用均衡控制效果
mEqualizer.setEnabled(true);
TextView eqTitle = new TextView(this);
eqTitle.setText("均衡器:");
layout.addView(eqTitle);
// 获取均衡控制器支持最小值和最大值
final short minEQLevel = mEqualizer.getBandLevelRange()[0];//第一个下标为最低的限度范围
short maxEQLevel = mEqualizer.getBandLevelRange()[1]; // 第二个下标为最高的限度范围
// 获取均衡控制器支持的全部频率
short brands = mEqualizer.getNumberOfBands();
for (short i = 0; i < brands; i++) {
TextView eqTextView = new TextView(this);
// 创建一个TextView。用于显示频率
eqTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
eqTextView.setGravity(Gravity.CENTER_HORIZONTAL);
// 设置该均衡控制器的频率
eqTextView.setText((mEqualizer.getCenterFreq(i) / 1000) + " Hz");
layout.addView(eqTextView);
// 创建一个水平排列组件的LinearLayout
LinearLayout tmpLayout = new LinearLayout(this);
tmpLayout.setOrientation(LinearLayout.HORIZONTAL);
// 创建显示均衡控制器最小值的TextView
TextView minDbTextView = new TextView(this);
minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
// 显示均衡控制器的最小值
minDbTextView.setText((minEQLevel / 100) + " dB");
// 创建显示均衡控制器最大值的TextView
TextView maxDbTextView = new TextView(this);
maxDbTextView.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
// 显示均衡控制器的最大值
maxDbTextView.setText((maxEQLevel / 100) + " dB");
LinearLayout.LayoutParams layoutParams = new
LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.weight = 1;
// 定义SeekBar做为调整工具
SeekBar bar = new SeekBar(this);
bar.setLayoutParams(layoutParams);
bar.setMax(maxEQLevel - minEQLevel);
bar.setProgress(mEqualizer.getBandLevel(i));
final short brand = i;
// 为SeekBar的拖动事件设置事件监听器
bar.setOnSeekBarChangeListener(new SeekBar
.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar,
int progress, boolean fromUser)
{
// 设置该频率的均衡值
mEqualizer.setBandLevel(brand,
(short) (progress + minEQLevel));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar)
{
}
@Override
public void onStopTrackingTouch(SeekBar seekBar)
{
}
});
// 使用水平排列组件的LinearLayout“盛装”3个组件
tmpLayout.addView(minDbTextView);
tmpLayout.addView(bar);
tmpLayout.addView(maxDbTextView);
// 将水平排列组件的LinearLayout加入到myLayout容器中
layout.addView(tmpLayout);
}
}
/**
* 初始化重低音控制器
*/
private void setupBassBoost()
{
// 以MediaPlayer的AudioSessionId创建BassBoost
// 相当于设置BassBoost负责控制该MediaPlayer
mBass = new BassBoost(0, mPlayer.getAudioSessionId());
// 设置启用重低音效果
mBass.setEnabled(true);
TextView bbTitle = new TextView(this);
bbTitle.setText("重低音:");
layout.addView(bbTitle);
// 使用SeekBar做为重低音的调整工具
SeekBar bar = new SeekBar(this);
// 重低音的范围为0~1000
bar.setMax(1000);
bar.setProgress(0);
// 为SeekBar的拖动事件设置事件监听器
bar.setOnSeekBarChangeListener(new SeekBar
.OnSeekBarChangeListener()
{
@Override
public void onProgressChanged(SeekBar seekBar,int progress,boolean fromUser)
{
// 设置重低音的强度
mBass.setStrength((short) progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar)
{
}
@Override
public void onStopTrackingTouch(SeekBar seekBar)
{
}
});
layout.addView(bar);
}
/**
* 初始化暂停和播放按钮
*/
private void setButton(){
final ImageButton btnPlay=new ImageButton(this);
btnPlay.setImageResource(R.drawable.play);
btnPlay.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
if(flag){
btnPlay.setImageResource(R.drawable.pause);
//mPlayer = MediaPlayer.create(getApplicationContext(), R.raw.red);
prepareMusic(music);
mPlayer.start();
flag=false;
}else{
btnPlay.setImageResource(R.drawable.play);
//mPlayer.release();
mPlayer.stop();
flag=true;
}
}
});
layout.addView(btnPlay);
}
/**
* 返回键销毁界面和音频,避免退出造成空指针错误
*/
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
SoundActivity.this.finish();
//mPlayer.release();
mPlayer.stop();
}
return super.onKeyDown(keyCode,event);
}
/**
* 准备播放音乐
*/
private void prepareMusic(String music){
try{
AssetFileDescriptor afd = am.openFd(music);
mPlayer.reset();
mPlayer.setDataSource(afd.getFileDescriptor()
,afd.getStartOffset()
,afd.getLength());
mPlayer.prepare();
}catch (IOException e){
e.printStackTrace();
}
}
public void onDestroy(){
super.onDestroy();
}
}
AndroidManifest.xml
清单文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="example.com.save">
<!--申请权限-->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SoundActivity"/>
<service
android:name=".RecordTimeService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.recordtimeservice" />
</intent-filter>
</service>
<receiver
android:name=".BootReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver
android:name=".HeadsetReceiver"
android:enabled="true"
android:exported="true" />
<receiver
android:name=".AlarmReceiver" />
<receiver
android:name=".TIME_TICK_Receiver"/>
</application>
</manifest>
缺点
- 频繁读取和写入文件可能造成内存泄露甚至削减存储卡的寿命
- 常驻后台服务降低手机性能,非正常消耗手机电量