startService和onBinderService混合开发音乐播放器
首先你你需要知道MediaPlayer这个类的一些方法:
- int getDuration():获取流媒体的总播放时长,单位是毫秒。
- int getCurrentPosition():获取当前流媒体的播放的位置,单位是毫秒。
- void seekTo(int msec):设置当前MediaPlayer的播放位置,单位是毫秒。
- void setLooping(boolean looping):设置是否循环播放。
- boolean isLooping():判断是否循环播放。
- boolean isPlaying():判断是否正在播放。
- void prepare():同步的方式装载流媒体文件。
- void prepareAsync():异步的方式装载流媒体文件。
- void release ():回收流媒体资源。
- void setAudioStreamType(int streamtype):设置播放流媒体类型。
- void setWakeMode(Context context, int mode):设置CPU唤醒的状态。
- setNextMediaPlayer(MediaPlayer next):设置当前流媒体播放完毕,下一个播放的MediaPlayer。
注意一下两点
- 在使用MediaPlayer播放一段流媒体的时候,需要使用prepare()或prepareAsync()方法把流媒体装载进MediaPlayer,才可以调用start()方法播放流媒体。
- setAudioStreamType()方法用于指定播放流媒体的类型,它传递的是一个int类型的数据,均以常量定义在AudioManager类中, 一般我们播放音频文件,设置为AudioManager.STREAM_MUSIC即可。
在播放下一首歌曲的时候需要释放MediaPlayer的资源:
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
然后就是关于BinderService:
-
先看一下按下Back键之后Activity的生命周期:onPause()-->onStop()-->onDestory()-->onCreate()-->onStart()-->onResum();
-
BinderService的存活于绑定的Activity有关,当与之绑定的Activity被销毁的时候,Service也会销毁,根据生命周期,我们就可以知道,当你按下Back键的时候,Service也会销毁,这样音乐就会停止播放,但是我们使用的大多数音乐播放器软件都按下Back键之后依旧在播放,所以,就有了我们的startServuce()和binderService()混合开发,因为startService()的生命周期与activity无关。
-
我们的主要逻辑是,用startService播放音乐,用binderService()控制音乐的播放。
-
startService很常见,就不说了,你需要知道binderService的使用,其实binderService就是用一个继承与BInder的MyBinder的类,作为一个中间对象,在Activity中对Service中的方法进行调用,从而实现控制。
下面我们开始编写我们的音乐播放器
创建一个MusicItem类记录一些音乐的信息
public class MusicItem {
public String name;
public String data;
public String artist;
public long time;
}
请求读写权限并且获取手机上的所有音频文件
private void initData(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (PackageManager.PERMISSION_DENIED == checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)){
requestPermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE},0);
}
}
itemList = new ArrayList<>();
new Thread(){
@Override
public void run() {
super.run();
ContentResolver resolver = mContext.getContentResolver();
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String[] objs ={
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.DURATION,
};
Cursor cursor = resolver.query(uri,objs,null,null,null);
if (cursor !=null){
while (cursor.moveToNext()){
MusicItem musicItem = new MusicItem();
itemList.add(musicItem);
String name = cursor.getString(0);
musicItem.name = name;
String data = cursor.getString(1);
musicItem.data = data;
String aritst = cursor.getString(2);
musicItem.artist = aritst;
long time = cursor.getLong(3);
musicItem.time = time;
}
cursor.close();
}
handler.sendEmptyMessage(0);
}
}.start();
}
获取到手机上的所有的音频文件之后,发送一个handler消息,将musicItem的集合itemList中的数据显示在Adapter上(Adapter的代码这里不拿出来说了,很见到的)
创建一个MusicService类,继承与Service
这个类用来后台播放音乐
public class MusicService extends Service {
private MediaPlayer player;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
@Override
public void onCreate() {
super.onCreate();
}
public void onPause(){
player.pause();
}
public void onStart(){
player.start();
}
public void openAudio(String uri) throws IOException {
if (player != null && player.isPlaying()){
player.stop();
player.release();
player = null;
}
player = new MediaPlayer();
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
player.setDataSource(uri);
player.prepare();
player.start();
} catch (IOException e) {
e.printStackTrace();
}
}
public class MyBinder extends Binder{
MusicService getService(){
return MusicService.this;
}
}
@Override
public void onDestroy() {
super.onDestroy();
player.stop();
player.reset();
player.release();
}
}
- MyBinder是Activity与MusicService进行通信的中间对象(这里只实现了播放和暂停的功能)
绑定MusicSerivce
下面是Activity的onCreate()方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
mContext = this;
lvList = (ListView) findViewById(R.id.lv_list);
Button start = (Button) findViewById(R.id.start);
Button pasue = (Button) findViewById(R.id.pause);
pasue.setOnClickListener(this);
start.setOnClickListener(this);
Intent intent = new Intent(MainActivity.this,MusicService.class);
startService(intent);
bindService(intent,conn,BIND_AUTO_CREATE);
initData();
}
绑定Service:
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
service1 = ((MusicService.MyBinder) service).getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
点击ListView中的Item的时候播放音乐
实现暂停和播放:
private android.os.Handler handler = new android.os.Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (itemList != null && itemList.size()>0){
MusicAdapter adapter = new MusicAdapter(mContext,itemList);
lvList.setAdapter(adapter);
lvList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
try {
service1.openAudio(itemList.get(position).data);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
};
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.start:
service1.onStart();
break;
case R.id.pause:
service1.onPause();
break;
}
}
- 当绑定成功的时候,返回的是一个MusicService对象,拿着这个Service对象就能对MusicService中的方法进行调用了。
- 首先startService,然后在binderService让Activity与Service之间进行通信,然Activity通过MyBinder对象对Service中的方法进行调用。
Service的销毁
在Activity中的onDestory()方法中对MusicService进行取消绑定:
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
记得添加读写权限