本片博客以一个简单的后台播放音乐demo来总结学习
本篇的总结请参照5W1H 分析法来阅读与学习:
Who (谁来做) When?(何时做) Where?(何地做) What? (做什么) Why? (为什么做) How? ( 怎么做)
在我们平常使用音乐播放器的时候,基本都有这么这个功能,用户离开了播放界面,而音乐却没有停止,还在继续播放,直到我们关闭了整个应用,音乐才消失。这个好奇的童鞋就会思考了。在后台播放音乐的是谁呢?它又是什么时候开始做的呢?在什么地方做的呢?它做了什么让音乐播放?为什么要这么做?又是具体怎么去做的呢?看完接下来的东西估计你就知道答案了。
先简单介绍Service:
Service
是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到 其他应用,服务仍将在后台继续运行。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例 如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。
Service的创建与启动
创建一个服务:MusicService
服务需要在配置文件中注册,当然,系统已经榜我们自动生成,简单看一下
<service
android:name=".service.MusicService"
android:enabled="true"
android:exported="true"></service>
我们的服务必须继承Service 必须重写onBind() 现在,我们已经创建好了一个服务Service
接下来我们看看怎么去启动我们的服务:
在启动服务之前先了解服务的生命周期
Service有两个周期 代表着服务的启动有两种方式:启动服务startService() 绑定服务bindService()
一:startService(): 随程序结束而结束
onCrate()--->onStartCommand()--->onDestroy()
onCreate():只会在服务第一次创建的时候调用,多次启动服务将不再执行
onStartCommand():多次调用 用于执行服务的逻辑 接收客户端发送过来的数据
onDestroy():服务结束时调用,用去销毁服务
二:bindService();随Activity结束而结束
onCrate()--->onbind()--->onDestroy()
onCreate():只会在服务第一次创建的时候调用,多次启动服务将不再执行
onbind():返回一个IBinder实列 用于返回Service向客户端传递数据
三:混合使用
onCrate()--->onStartCommand()--->onbind()--->onDestroy()
客户端与服务的通信,
分为三个点
1.启动服务startService() 客户端向服务发送数据
客户端发送
服务接收
总结:启动服务非常方便客户端向服务中传输数据,通过Intent对象携带数据,在onStartCommand()中接收数据,
如果想返回信息的话,1)可以在服务中使用Message来发送异步消息,在客户端通过Handler来接收数据
2)可以使用广播携带数据(具体的使用在学习吧)
2.绑定服务bindService() 服务向客户端发送数据
绑定服务:代码有点多,注释解释
public class MainActivity extends AppCompatActivity {
private Button but_start;
private MusicService.MusicBinder musicBinder;
//用于服务连接 当连接成功时可以返回Service中我们想要的东西,比如播放状态,播放的时间,音乐的长度
//还可以通过这个方法来控制Service中的逻辑
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//绑定成功回调
musicBinder = (MusicService.MusicBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
//绑定失败
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initDtat();
Intent intent = new Intent(MainActivity.this, MusicService.class);
//这里我传入一个音乐的url
// intent.putExtra("musicUrl","https://api.bzqll.com/music/netease/url?id=574566207&key=579621905");
// startService(intent);
//第一个值:Intent对象 第二个值:ServiceConnection对象 第三个值,可以自动绑定创建
bindService(intent,serviceConnection,BIND_AUTO_CREATE);
}
private void initView() {
but_start = findViewById(R.id.but_start);
}
private void initDtat() {
but_start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
musicBinder.play();
}
});
}
}
服务传数据:
public class MusicService extends Service {
private MediaPlayer mediaPlayer;
//服务第一次创建的时候调用,这里声明一个音乐对象
@Override
public void onCreate() {
super.onCreate();
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource("https://api.bzqll.com/music/netease/url?id=574566207&key=579621905");
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
//在通过bindService()绑定服务的时候将不会调用此方法
// @Override
// public int onStartCommand(Intent intent, int flags, int startId) {
// String url = intent.getStringExtra("musicUrl");
// Log.e("onStartCommand","-------------------"+url);
// mediaPlayer = new MediaPlayer();
// try {
// mediaPlayer.setDataSource(url);
// mediaPlayer.prepare();
// mediaPlayer.start();
// } catch (IOException e) {
// e.printStackTrace();
// }
// return super.onStartCommand(intent, flags, startId);
// }
//返回一个IBinder对象,所以我们在下方创建一个IBinder对象,用于反馈数据
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return new MusicBinder();
}
//在这个对象中,我们不仅可以通过相应的方法控制音乐,还可以通过其中的方法得到我们想要的数据
//比如音乐时间,播放状态,里面的方法可以自由添加以满足自己的需求
public class MusicBinder extends Binder{
//播放状态
public boolean playing(){
return mediaPlayer.isPlaying();
}
public void play() {
mediaPlayer.start();//开启音乐
}
public void pause() {
mediaPlayer.pause();//暂停音乐
}
public long getMusicDuration() {
return mediaPlayer.getDuration();//获取文件的总长度
}
public long getPosition() {
return mediaPlayer.getCurrentPosition();//获取当前播放进度
}
}
//当服务销毁时释放资源
@Override
public void onDestroy() {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
}
mMediaPlayer.release();
mMediaPlayer = null;
timer.cancel();
task.cancel();
super.onDestroy();
}
}
总结:通过绑定服务的方式我们可以自由回去数据与控制相应的内容。当我们有一个播放列表的时候,我们需要不停的往Service里面传送音乐url来播放相应的歌曲,这个时候就会发现,不知道在Service中那里来获取我们的数据,脑壳疼。。。。于是,就有了下面一种方式,将startService()+bindService() 一起使用,这样我们既可以自由的发送数据,还可以自由的从Service中得到我们想要的数据以及对Service的控制。
3.启动后绑定startService()+bindService() 客户端向服务发送数据,服务反馈数据
直接看代码,与上面的大同小异
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Button but_start;
private Intent intent;
private MusicService.MusicBinder musicBinder;
//由于服务连接 当连接成功时可以返回Service中我们想要的东西,比如播放状态,播放的时间,音乐的长度
//还可以通过这个方法来控制Service中的逻辑
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//绑定成功回调
musicBinder = (MusicService.MusicBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initDtat();
intent = new Intent(MainActivity.this, MusicService.class);
//这里我传入一个音乐的url
intent.putExtra("musicUrl","https://api.bzqll.com/music/netease/url?id=574566207&key=579621905");
startService(intent);
//第一个值:Intent对象 第二个值:ServiceConnection对象 第三个值,可以自动绑定创建
bindService(intent,serviceConnection,BIND_AUTO_CREATE);
}
private void initView() {
but_start = findViewById(R.id.but_start);
}
private void initDtat() {
but_start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
musicBinder.play();
}
});
}
@Override
protected void onDestroy() {
stopService(intent);
unbindService(serviceConnection);
super.onDestroy();
}
}
MusicService.java
public class MusicService extends Service {
private MediaPlayer mediaPlayer;
@Override
public void onCreate() {
super.onCreate();
// mediaPlayer = new MediaPlayer();
// try {
// mediaPlayer.setDataSource("https://api.bzqll.com/music/netease/url?id=574566207&key=579621905");
// mediaPlayer.prepare();
// } catch (IOException e) {
// e.printStackTrace();
// }
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String url = intent.getStringExtra("musicUrl");
Log.e("onStartCommand","-------------------"+url);
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDataSource(url);
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IOException e) {
e.printStackTrace();
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return new MusicBinder();
}
public class MusicBinder extends Binder{
//播放状态
public boolean playing(){
return mediaPlayer.isPlaying();
}
public void play() {
mediaPlayer.start();//开启音乐
}
public void pause() {
mediaPlayer.pause();//暂停音乐
}
public long getMusicDuration() {
return mediaPlayer.getDuration();//获取文件的总长度
}
public long getPosition() {
return mediaPlayer.getCurrentPosition();//获取当前播放进度
}
}
//当服务销毁时释放资源
@Override
public void onDestroy() {
if (mMediaPlayer.isPlaying()) {
mMediaPlayer.stop();
}
mMediaPlayer.release();
mMediaPlayer = null;
timer.cancel();
task.cancel();
super.onDestroy();
}
}
到此Service的简单使用就这样,如果感兴趣的话可以试试回答上面的 5W1H