「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」
Android Service实践实例
音乐播放器
分别使用startService和bindService来启动本地服务
我们首先从startService启动Service学起
Activity
public class PlayMusic extends Activity implements OnClickListener {
private static final String TAG = "PlayMusic";
private Button playBtn;
private Button stopBtn;
private Button pauseBtn;
private Button exitBtn;
private Button closeBtn;
//....(详见源码)
@Override
public void onClick(View v) {
int op = -1;
Intent intent = new Intent("org.allin.android.musicService");
//广播用
// Intent intent = new Intent("org.allin.android.musicReceiver");
switch (v.getId()) {
case R.id.play:
Log.d(TAG, "onClick: playing muic");
op = 1;
break;
case R.id.stop:
Log.d(TAG, "onClick: stoping music");
op = 2;
break;
case R.id.pause:
Log.d(TAG, "onClick: pausing music");
op = 3;
break;
case R.id.close:
Log.d(TAG, "onClick: close");
this.finish();
break;
case R.id.exit:
Log.d(TAG, "onClick: exit");
op = 4;
stopService(intent);
this.finish();
break;
}
Bundle bundle = new Bundle();
bundle.putInt("op", op);
intent.putExtras(bundle);
startService(intent);
// sendBroadcast(intent);
}
}
通过重写onClick方法来实现对播放音乐的控制:
- 把播放音乐的各种操作用数字的方式通过Intent传递给service
- 构造一个Intent ,ntent intent = new Intent("org.allin.android.musicService")
- "org.allin.android.musicService"是在AndroidManifest.xml文件中对service类的定义
<service android:enabled="true" android:name=".MusicService">
<intent-filter>
<action android:name="org.allin.android.musicService" />
</intent-filter>
</service>
Service
把操作码放在Bundle中: Bundle bundle = new Bundle(); bundle.putInt("op", op); intent.putExtras(bundle); 最后使用startService(intent);启动服务。
MusicService.java
public class MusicService extends Service {
private static final String TAG = "MyService";
private MediaPlayer mediaPlayer;
/*
* (non-Javadoc)
*
* @see android.app.Service#onBind(android.content.Intent)
*/
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onCreate() {
Log.v(TAG, "onCreate");
if (mediaPlayer == null) {
mediaPlayer = MediaPlayer.create(this, R.raw.tmp);
mediaPlayer.setLooping(false);
}
}
@Override
public void onDestroy() {
Log.v(TAG, "onDestroy");
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
@Override
public void onStart(Intent intent, int startId) {
Log.v(TAG, "onStart");
if (intent != null) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
int op = bundle.getInt("op");
switch (op) {
case 1:
play();
break;
case 2:
stop();
break;
case 3:
pause();
break;
}
}
}
}
public void play() {
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
public void pause() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
public void stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
try {
// 在调用stop后如果需要再次通过start进行播放,需要之前调用prepare函数
mediaPlayer.prepare();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
使用了系统自带MediaPlayer进行音乐的播放控制。
当调用了startService后服务会先调用onCreate,我们在里面对MediaPlayer进行初始化。接着会调用onStart,可以看到传递给startService()的Intent对象会传递给onStart()方法,这样我们就可以得到intent里面的操作码: Iundle bundle = intent.getExtras(); int op = bundle.getInt("op");
BroadcastReceiver
有时候如果服务只提供一些操作接口,则可以通过广播的方式来启动服务。
首先要定义一个Receiver,并继承BroadcastReceiver,然后在AndroidManifest.xml中进行注册:
<receiver android:name=".MusicReceiver">
<intent-filter>
<action android:name="org.allin.android.musicReceiver" />
</intent-filter>
</receiver>
MusicReceiver.java
public class MusicReceiver extends BroadcastReceiver {
private static final String TAG = "MusicReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive");
Intent it = new Intent("org.allin.android.musicService");
Bundle bundle = intent.getExtras();
it.putExtras(bundle);
if(bundle != null){
int op = bundle.getInt("op");
if(op == 4){
context.stopService(it);
}else{
context.startService(it);
}
}
}
}
然后对PlayMusic中的onclick方法进行些改造,把Intent指向Receiver Intent intent = new Intent("org.allin.android.musicReceiver"); intent中绑定的操作码都不变,再调用sendBroadcast(intent);把intentg广播出去。 当MusicReceiver接受到广播后根据操作码进行相应的操作。
使用bindService来启动Service
Activity
public class PlayBindMusic extends Activity implements OnClickListener {
private static final String TAG = "PlayBindMusic";
private Button playBtn;
private Button stopBtn;
private Button pauseBtn;
private Button exitBtn;
private BindMusicService musicService;
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.play:
Log.d(TAG, "onClick: binding srvice");
musicService.play();
break;
case R.id.stop:
Log.d(TAG, "onClick: stoping srvice");
if(musicService != null){
musicService.stop();
}
break;
case R.id.pause:
Log.d(TAG, "onClick: pausing srvice");
if(musicService != null){
musicService.pause();
}
break;
case R.id.exit:
Log.d(TAG, "onClick: exit");
this.finish();
break;
}
}
private void connection(){
Log.d(TAG, "connecting.....");
Intent intent = new Intent("org.allin.android.bindService");
bindService(intent, sc, Context.BIND_AUTO_CREATE);
}
private ServiceConnection sc = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
musicService = null;
Log.d(TAG, "in onServiceDisconnected");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
musicService = ((BindMusicService.MyBinder)(service)).getService();
if(musicService != null){
musicService.play();
}
Log.d(TAG, "in onServiceConnected");
}
};
}
这里使用了bindService(intent, sc, Context.BIND_AUTO_CREATE);来启动服务的, 我们需要定义ServiceConnectionnn,并实现里面的方法,当服务绑定成功后会调用ServiceConnectionnn中的回调函数: public void onServiceConnected(ComponentName name, IBinder service), 回调函数里面使用musicService = ((BindMusicService.MyBinder)(service)).getService();来获取BindMusicService服务对象,有了BindMusicService实例对象,就可以调用服务提供的各种控制音乐播放的功能。
BindMusicService.java
public class BindMusicService extends Service {
private static final String TAG = "MyService";
private MediaPlayer mediaPlayer;
private final IBinder binder = new MyBinder();
public class MyBinder extends Binder {
BindMusicService getService() {
return BindMusicService.this;
}
}
/*
* (non-Javadoc)
*
* @see android.app.Service#onBind(android.content.Intent)
*/
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
play();
return binder;
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
Toast.makeText(this, "show media player", Toast.LENGTH_SHORT).show();
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
Toast.makeText(this, "stop media player", Toast.LENGTH_SHORT);
if(mediaPlayer != null){
mediaPlayer.stop();
mediaPlayer.release();
}
}
public void play() {
if (mediaPlayer == null) {
mediaPlayer = MediaPlayer.create(this, R.raw.tmp);
mediaPlayer.setLooping(false);
}
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
public void pause() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
public void stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
try {
// 在调用stop后如果需要再次通过start进行播放,需要之前调用prepare函数
mediaPlayer.prepare();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
可以看到Service中有个返回IBinder对象的onBind方法,这个方法会在Service被绑定到其他程序上时被调用,而这个IBinder对象和之前看到的onServiceConnected方法中传入的那个IBinder是同一个东西。应用和Service间就依靠这个IBinder对象进行通信。
下一篇将会介绍通过AIDL对Service进行远程调用。