移动辅助类App编程项目

文章目录

  • 移动辅助类App编程项目
    • 软件说明
    • 实现功能
    • 源代码
      • `layout_main.xml`静态界面布局文件
      • `MainActivity`主界面
      • `RecordTimeService`服务
      • `AlarmReceiver`广播接收器
      • `FileProcess`静态方法
      • `OnHeadsetListener`接口(interface)
      • `HeadsetReceiver`耳机广播接收器
      • `BootReceiver`开机广播接收器
      • `TIME_TICK_Receiver`广播接收器
      • `SoundActivity`动态界面
      • `AndroidManifest.xml`清单文件
    • 缺点

基础:掌握Android编程,java程序设计,嵌入式开发

  1. Android编程:学会简单的UI编程,能够设计XML静态界面布局以及动态更新界面,
    熟悉Android四大组件Activity、Service、Broadcast、ContentProvider以及intent消息意图,实现组件之间的通信
  2. java程序设计:面向对象编程,多线程机制,文件字节字符流输入输出流读写文件,接口与多态

开发软件:Android studio x64

软件说明

本软件设计的目的是防止用户沉迷于耳机。首先设定一个提示时间(建议不超过60分钟), 然后点击开启服务,当佩戴耳机达到预定上限时会自动连续播放一段音频以提示用户。拔下耳机,音频外放一次自动关闭,可以选择清零或者设置更长的限制时间关闭提示。为正常使用软件需获取自启动权限,为避免频繁刷新而删除任务,需要使软件锁定在后台。如果用户不需要使用,可以选择卸载或者关闭自启动功能

实现功能

  1. 判断耳机断开与连接(蓝牙耳机或有线耳机)
  2. AlarmService实现定时操作
  3. 软件服务常驻后台
  4. 音效均衡器处理单个音频

源代码

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"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"android:layout_marginRight="100sp"android:layout_marginEnd="100sp"><TextViewandroid:textSize="18sp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="今日佩戴耳机时长:"/><TextViewandroid:textSize="20sp"android:text="暂无数据"android:id="@+id/tv_time"android:layout_width="wrap_content"android:layout_height="wrap_content" /></LinearLayout><RelativeLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="20sp"><EditTextandroid:inputType="number"android:id="@+id/ettv_limit"android:hint="请输入提示时间(分钟)"android:layout_width="fill_parent"android:layout_height="wrap_content" /><Buttonandroid: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><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"android:layout_marginTop="50sp"><Buttonandroid:id="@+id/bt_clear"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="清零"android:onClick="onClick"/><Buttonandroid:id="@+id/bt_read"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="帮助"android:onClick="onClick"/></LinearLayout><Buttonandroid:id="@+id/bt_start"android:layout_marginTop="100sp"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="开启计时服务"android:onClick="onClick"/><Buttonandroid:id="@+id/bt_get"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="获取自启动权限"android:onClick="onClick"/><Buttonandroid: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;@Overrideprotected 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"://360componentName = 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;// 长时间计时任务AlarmManagerprivate AlarmManager manager;private PendingIntent pi;// 音频控制private AudioManager audioManager;public RecordTimeService() {}@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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 {@Overridepublic 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;@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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;// 定义播放声音的MediaPlayerprivate MediaPlayer mPlayer;// 定义系统的均衡器private Equalizer mEqualizer;// 定义系统的重低音控制器private BassBoost mBass;// 定义线性布局private LinearLayout layout;@Overrideprotected 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() {@Overridepublic void onCompletion(MediaPlayer mp) {prepareMusic(music);mPlayer.start();}});// 初始化均衡控制器setupEqualizer();// 初始化重低音控制器setupBassBoost();// 初始化按钮setButton();//mPlayer.start();}private void setupEqualizer(){// 每个MediaPlayer都有自己独一无二的SessionId// 以MediaPlayer的AudioSessionId创建Equalizer// 相当于设置Equalizer负责控制该MediaPlayermEqualizer = 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);// 创建一个水平排列组件的LinearLayoutLinearLayout tmpLayout = new LinearLayout(this);tmpLayout.setOrientation(LinearLayout.HORIZONTAL);// 创建显示均衡控制器最小值的TextViewTextView minDbTextView = new TextView(this);minDbTextView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT));// 显示均衡控制器的最小值minDbTextView.setText((minEQLevel / 100) + " dB");// 创建显示均衡控制器最大值的TextViewTextView 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 = newLinearLayout.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(){@Overridepublic void onProgressChanged(SeekBar seekBar,int progress, boolean fromUser){// 设置该频率的均衡值mEqualizer.setBandLevel(brand,(short) (progress + minEQLevel));}@Overridepublic void onStartTrackingTouch(SeekBar seekBar){}@Overridepublic 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负责控制该MediaPlayermBass = 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~1000bar.setMax(1000);bar.setProgress(0);// 为SeekBar的拖动事件设置事件监听器bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){@Overridepublic void onProgressChanged(SeekBar seekBar,int progress,boolean fromUser){// 设置重低音的强度mBass.setStrength((short) progress);}@Overridepublic void onStartTrackingTouch(SeekBar seekBar){}@Overridepublic 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(){@Overridepublic 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" /><applicationandroid: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"/><serviceandroid:name=".RecordTimeService"android:enabled="true"android:exported="true"><intent-filter><action android:name="android.intent.action.recordtimeservice" /></intent-filter></service><receiverandroid:name=".BootReceiver"android:enabled="true"><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED" /></intent-filter></receiver><receiverandroid:name=".HeadsetReceiver"android:enabled="true"android:exported="true" /><receiverandroid:name=".AlarmReceiver" /><receiverandroid:name=".TIME_TICK_Receiver"/></application></manifest>

缺点

  1. 频繁读取和写入文件可能造成内存泄露甚至削减存储卡的寿命
  2. 常驻后台服务降低手机性能,非正常消耗手机电量

记录佩戴耳机时长App开发相关推荐

  1. 【Android开发】微信精选,文章资讯类App开发记录总结

    缘起 微信精选的App开发来源是在聚合数据上看到了有免费的微信精选的数据接口,无限调用.相对于其他的诸如违章查询,医药查询,NBA赛事等等,我感觉还是微信文章精选这个数据接口离我最近,所以想着拿着个数 ...

  2. APP开发项目流程详解,长知识了!

    APP的开发流程并不复杂,APP开发人员一般都包含着UI设计师 .前端开发.后端开发.测试专员.产品经理等等. 而根据开发人员的分工不同,可以把APP的开发项目流程分为三个阶段:需求阶段–开发阶段–发 ...

  3. App开发-使用Vue3+Vant组件实现历史搜索记录功能

    使用Vue3+Vant组件实现App历史搜索记录功能 最近在开发一款新的app项目,我自己也是第一次接触app开发,经过团队的一段时间研究调查,决定使用Vue3+Vant前端组件的模式进行开发,vue ...

  4. android开发入门与实践_我的新书《Android App开发入门与实战》已经出版

    前言 工作之余喜欢在CSDN平台上写一些技术文章,算下时间也有两三年了.写文章的目的一方面是自己对技术的总结,另一方面也是将平时遇到的问题和解决方案与大家分享,还有就是在这个平台上能和大家共同交流. ...

  5. 蓝牙运动手环app开发方案

    所谓智能蓝牙手环app软件开发,  就是内置蓝牙操作系统.通过连接网络来实现多种功能的手环产品,蓝牙手环一般能同步手机中的电话.短信.邮件.照片.音乐等相关数据.其实早在1982年,日本精工就通过其收 ...

  6. 【Android】App开发-动画效果篇

    在我们玩手机的过程中,如果我们点击某一个页面时,会出现一个页面动画加载或者动画效果的现象.现在我们就来看看App开发中是如何实现动画效果的. 目录 动画的分类 逐帧动画: 补间动画: 动画的分类 在常 ...

  7. 安卓物联网APP开发——基于编辑物联网平台环境实现远程控制数据传输

    本篇博客主要对app进行开发来实现对esp系列芯片的远程控制,通过mqtt协议来进行数据的传输,用wifi模块接收数据串口收发数据到单片机上使用,可远程操控. APP开发(Android Studio ...

  8. 桃词典 Peach Dictionary 简易英语词典app开发 安卓软件开发 The End 导航页及收尾工作

    导航: 桃词典 Peach Dictionary 简易英语词典app开发 安卓软件开发 Part 1 桃词典 Peach Dictionary 简易英语词典app开发 安卓软件开发 Part 2 桃词 ...

  9. 无线蓝牙耳机手机端app开发_汪峰耗时1500天造了一款耳机,秒杀苹果AirPods!

    每天带着有线耳机追公交的小黑 因为耳机线跟不上小编贴地飞行的速度 总是被甩出去 为此 一个月光是耳机就换了三四副 每次从包包里拿出来耳机,明明整理好的耳机线,又揉成了一团! 某水果公司也发现了有线耳机 ...

最新文章

  1. 交换一个整数二进制表示中的奇数位和偶数位
  2. python类型转换-Python的数据类型转换函数
  3. context:annotation-config / 和context:component-
  4. linux sed 找出前后三行,Linux Sed 使用示例
  5. 爱酷pro充电测试软件,iQOO 5 Pro续航、充电测试简报
  6. redhat编译安装git
  7. mysql 事件里定义事物_聊一聊 MySQL 中的事务及其实现原理
  8. Http(s)与后台交互方式
  9. php 控制器分组模式,控制器分组路由
  10. Reader entry: ���� 乱码
  11. consul mysql 检查_MySQL在Consul服务中的健康检查逻辑
  12. 鱼群算法matlab代码,人工鱼群算法MATLAB实现
  13. 大学排行榜 : qs全球世界 大学排行榜
  14. 在Unity中模拟汽车的移动
  15. matlab 文本框方向,ppt文本框文字方向为所有文字旋转的设置方法
  16. 习题 6.13 编一程序,将两个字符串连接起来,不要用strcat函数。
  17. GJM : AlloyTouch实战--60行代码搞定QQ看点资料卡
  18. 请教税控开票数据aardio如何连接
  19. 搞不定Excel没关系,这款神器让你秒变数据可视化高手
  20. Scala初级实践——统计手机耗费流量(1)

热门文章

  1. 三分钟了解JVM的垃圾回收和三色标记
  2. 我的大学(2001-2005,从文艺青年到2B青年)
  3. 站在孙正义愿景基金背后的男人:他们才是软银科技版图的真正操盘手
  4. lammps模拟中tersoff势设置方法
  5. EventBus的介绍
  6. 华为ospf模拟器命令笔记(1)
  7. Gson踩坑笔记:为什么对象的构造方法没有被执行?
  8. Android中的Picasso实现圆角图片
  9. 就在本周末!北美最牛X的餐饮大咖都找齐了,值得你来朝圣这一次
  10. 计算机软故障分为哪几种,计算机常见故障可分为硬件和软件故障,具体介绍