当前位置: 代码迷 >> Android >> android service 学习(下)
  详细解决方案

android service 学习(下)

热度:73   发布时间:2016-05-01 19:01:23.0
android service 学习(上)

引用:http://www.cnblogs.com/allin/archive/2010/05/15/1736458.html

?
Service是android?系统中的一种组件,它跟Activity的级别差不多,但是他不能自己运行,只能后台运行,并且可以和其他组件进行交互。Service的启动有两种方式:context.startService() context.bindService()。
?
使用context.startService() 启动Service是会会经历:
context.startService() ?->onCreate()- >onStart()->Service running
context.stopService() | ->onDestroy() ->Service stop?
?
如果Service还没有运行,则android先调用onCreate()然后调用onStart();如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。?
?
stopService的时候直接onDestroy,如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。该Service的调用者再启动起来后可以通过stopService关闭Service。
?
所以调用startService的生命周期为:onCreate --> onStart(可多次调用) --> onDestroy
?
使用使用context.bindService()启动Service会经历:
context.bindService()->onCreate()->onBind()->Service running
onUnbind() -> onDestroy() ->Service stop
?
onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。?
??????
所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。
?
在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。
?
service可以在和多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务嘛,总是藏在后头的。
?
下面我做了一个简单的音乐播放的应用,分别使用startService和bindService来启动本地的服务。
而在下一篇《android service 学习(下)?》会介绍通过AIDL对Service进行远程调用。
?
下面是整个应用启动界面:
先从使用startService启动Service学起
?
?
首先编写一个Activity

01public class PlayMusic extends Activity implements OnClickListener {
02????private static final String TAG = "PlayMusic";
03????private Button playBtn;
04????private Button stopBtn;
05????private Button pauseBtn;
06????private Button exitBtn;
07????private Button closeBtn;
08?
09????//....(详见源码)
10?
11@Override
12????public void onClick(View v) {
13????????int op = -1;
14????????Intent intent = new Intent("org.allin.android.musicService");
15?????????
16????????//广播用
17//????? Intent intent = new Intent("org.allin.android.musicReceiver");
18?????????
19????????switch (v.getId()) {
20????????case R.id.play:
21????????????Log.d(TAG, "onClick: playing muic");
22????????????op = 1;
23????????????break;
24????????case R.id.stop:
25????????????Log.d(TAG, "onClick: stoping music");
26????????????op = 2;
27????????????break;
28????????case R.id.pause:
29????????????Log.d(TAG, "onClick: pausing music");
30????????????op = 3;
31????????????break;
32????????case R.id.close:
33????????????Log.d(TAG, "onClick: close");
34????????????this.finish();
35????????????break;
36????????case R.id.exit:
37????????????Log.d(TAG, "onClick: exit");
38????????????op = 4;
39????????????stopService(intent);
40????????????this.finish();
41????????????break;
42????????}
43?????????
44????????Bundle bundle? = new Bundle();
45????????bundle.putInt("op", op);
46????????intent.putExtras(bundle);
47????????startService(intent);
48?????????
49//????? sendBroadcast(intent);
50????}
51?
52?
53}


?
通过重写onClick方法来实现对播放音乐的控制。这里把播放音乐的各种操作用数字的方式通过Intent传递给service。?
构造一个Intent ,ntent intent = new Intent("org.allin.android.musicService");
"org.allin.android.musicService"是在AndroidManifest.xml文件中对service类的定义

1<service android:enabled="true" android:name=".MusicService">
2<intent-filter>
3<action android:name="org.allin.android.musicService" />
4</intent-filter>
5</service>

把操作码放在Bundle中?
Bundle bundle ?= new Bundle();
bundle.putInt("op", op);
intent.putExtras(bundle);
最后使用startService(intent);启动服务。?
下面看看Service是怎么实现的。
?
MusicService.java
?

01/**
02?* @author allin.dev
03?* http://allin.cnblogs.com/
04?*
05?*/
06public class MusicService extends Service {
07?
08????private static final String TAG = "MyService";
09????private MediaPlayer mediaPlayer;
10?
11????/*
12?????* (non-Javadoc)
13?????*
14?????* @see android.app.Service#onBind(android.content.Intent)
15?????*/
16????@Override
17????public IBinder onBind(Intent arg0) {
18????????return null;
19????}
20?
21????@Override
22????public void onCreate() {
23????????Log.v(TAG, "onCreate");
24????????if (mediaPlayer == null) {
25????????????mediaPlayer = MediaPlayer.create(this, R.raw.tmp);
26????????????mediaPlayer.setLooping(false);
27????????}
28????}
29?
30????@Override
31????public void onDestroy() {
32????????Log.v(TAG, "onDestroy");
33????????if (mediaPlayer != null) {
34????????????mediaPlayer.stop();
35????????????mediaPlayer.release();
36????????}
37????}
38?
39????@Override
40????public void onStart(Intent intent, int startId) {
41????????Log.v(TAG, "onStart");
42????????if (intent != null) {
43????????????Bundle bundle = intent.getExtras();
44????????????if (bundle != null) {
45?
46????????????????int op = bundle.getInt("op");
47????????????????switch (op) {
48????????????????case 1:
49????????????????????play();
50????????????????????break;
51????????????????case 2:
52????????????????????stop();
53????????????????????break;
54????????????????case 3:
55????????????????????pause();
56????????????????????break;
57????????????????}
58?
59????????????}
60????????}
61?
62????}
63?
64????public void play() {
65????????if (!mediaPlayer.isPlaying()) {
66????????????mediaPlayer.start();
67????????}
68????}
69?
70????public void pause() {
71????????if (mediaPlayer != null && mediaPlayer.isPlaying()) {
72????????????mediaPlayer.pause();
73????????}
74????}
75?
76????public void stop() {
77????????if (mediaPlayer != null) {
78????????????mediaPlayer.stop();
79????????????try {
80????????????????// 在调用stop后如果需要再次通过start进行播放,需要之前调用prepare函数
81????????????????mediaPlayer.prepare();
82????????????} catch (IOException ex) {
83????????????????ex.printStackTrace();
84????????????}
85????????}
86????}
87?
88}

?
?
服务?使用了系统自带MediaPlayer进行音乐的播放控制。?当调用了startService后服务会先调用onCreate,我们在里面对MediaPlayer进行初始化。接着会调用onStart,可以看到传递给startService()的Intent对象会传递给onStart()方法,这样我们就可以得到intent里面的操作码:?
Iundle bundle = intent.getExtras();?
int op = bundle.getInt("op");
然后更具定义好的操作码进行相应的f播放操作。启动后界面如下图:?
?
图中的”close”和“exit”是不同的,close只是调用finish()退出当前的Activity,但是Service并没有关掉,音乐会继续播放。而exit就是调用了stopService(intent);来停止服务,Service会调用onDestroy()方法来对mediaPlayer进行停止和释放资源。
?
有时候如果服务只提供一些操作接口,我们也可以通过广播的g方式来启动服务。
首先要定义一个Receiver,并继承BroadcastReceiver,然后在AndroidManifest.xml中进行注册:

1<receiver android:name=".MusicReceiver">
2<intent-filter>
3<action android:name="org.allin.android.musicReceiver" />
4</intent-filter>
5</receiver>

?
Receiver的实现:
?
MusicReceiver.java

01/**
02?* @author allin.dev
03?* http://allin.cnblogs.com/
04?*
05?*/
06public class MusicReceiver extends BroadcastReceiver {
07?
08????private static final String TAG = "MusicReceiver";
09????@Override
10????public void onReceive(Context context, Intent intent) {
11????????Log.d(TAG, "onReceive");
12????????Intent it = new Intent("org.allin.android.musicService");
13????????Bundle bundle = intent.getExtras();
14????????it.putExtras(bundle);
15?????????
16????????if(bundle != null){
17????????????int op = bundle.getInt("op");
18????????????if(op == 4){
19????????????????context.stopService(it);
20????????????}else{
21????????????????context.startService(it);
22????????????}
23????????}
24?????????
25????}
26?
27}

?
然后对PlayMusic中的onclick方法进行些改造,把Intent指向Receiver
Intent intent = new Intent("org.allin.android.musicReceiver");
intent中绑定的操作码都不变,再调用sendBroadcast(intent);把intentg广播出去。
MusicReceiver接受到广播后根据操作码进行相应的操作。




接下来的例子就是使用bindService来启动Service
首先一样是写一个Activity

01public class PlayBindMusic extends Activity implements OnClickListener {
02?
03????private static final String TAG = "PlayBindMusic";
04????private Button playBtn;
05????private Button stopBtn;
06????private Button pauseBtn;
07????private Button exitBtn;
08?????
09????private BindMusicService musicService;
10?
11????@Override
12????public void onClick(View v) {
13?
14????????switch (v.getId()) {
15????????case R.id.play:
16????????????Log.d(TAG, "onClick: binding srvice");
17????????????musicService.play();
18????????????break;
19????????case R.id.stop:
20????????????Log.d(TAG, "onClick: stoping srvice");
21????????????if(musicService != null){
22????????????????musicService.stop();
23????????????}
24????????????break;
25????????case R.id.pause:
26????????????Log.d(TAG, "onClick: pausing srvice");
27????????????if(musicService != null){
28????????????????musicService.pause();
29????????????}
30????????????break;
31????????case R.id.exit:
32????????????Log.d(TAG, "onClick: exit");
33????????????this.finish();
34????????????break;
35????????}
36????}
37?
38?
39private void connection(){
40????????Log.d(TAG, "connecting.....");
41????????Intent intent = new Intent("org.allin.android.bindService");
42????????bindService(intent, sc, Context.BIND_AUTO_CREATE);
43?????????
44????}
45private ServiceConnection sc = new ServiceConnection() {
46????????@Override
47????????public void onServiceDisconnected(ComponentName name) {
48????????????musicService = null;
49????????????Log.d(TAG, "in onServiceDisconnected");
50????????}
51?????????
52????????@Override
53????????public void onServiceConnected(ComponentName name, IBinder service) {
54????????????musicService = ((BindMusicService.MyBinder)(service)).getService();
55????????????if(musicService != null){
56????????????????musicService.play();
57????????????}
58?????????????
59????????????Log.d(TAG, "in onServiceConnected");
60????????}
61????};
62}

?

?

这里使用了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的实现:

?

?

01/**
02?* @author allin.dev
03?* http://allin.cnblogs.com/
04?*/
05public class BindMusicService extends Service {
06?
07????private static final String TAG = "MyService";
08????private MediaPlayer mediaPlayer;
09?
10????private final IBinder binder = new MyBinder();
11?
12????public class MyBinder extends Binder {
13????????BindMusicService getService() {
14????????????return BindMusicService.this;
15????????}
16????}
17?
18????/*
19?????* (non-Javadoc)
20?????*
21?????* @see android.app.Service#onBind(android.content.Intent)
22?????*/
23????@Override
24????public IBinder onBind(Intent intent) {
25????????Log.d(TAG, "onBind");
26????????play();
27????????return binder;
28????}
29?
30????@Override
31????public void onCreate() {
32????????super.onCreate();
33?????????
34????????Log.d(TAG, "onCreate");
35????????Toast.makeText(this, "show media player", Toast.LENGTH_SHORT).show();
36?????????
37?????????
38????}
39?
40????@Override
41????public void onDestroy() {
42????????super.onDestroy();
43?????????
44????????Log.d(TAG, "onDestroy");
45????????Toast.makeText(this, "stop media player", Toast.LENGTH_SHORT);
46????????if(mediaPlayer != null){
47????????????mediaPlayer.stop();
48????????????mediaPlayer.release();
49????????}
50????}
51?
52?????
53????public void play() {
54????????if (mediaPlayer == null) {
55????????????mediaPlayer = MediaPlayer.create(this, R.raw.tmp);
56????????????mediaPlayer.setLooping(false);
57????????}
58????????if (!mediaPlayer.isPlaying()) {
59????????????mediaPlayer.start();
60????????}
61????}
62?
63????public void pause() {
64????????if (mediaPlayer != null && mediaPlayer.isPlaying()) {
65????????????mediaPlayer.pause();
66????????}
67????}
68?
69????public void stop() {
70????????if (mediaPlayer != null) {
71????????????mediaPlayer.stop();
72????????????try {
73????????????????// 在调用stop后如果需要再次通过start进行播放,需要之前调用prepare函数
74????????????????mediaPlayer.prepare();
75????????????} catch (IOException ex) {
76????????????????ex.printStackTrace();
77????????????}
78????????}
79????}
80?
81}



我们看到Service中有个返回IBinder对象的onBind方法,这个方法会在Service被绑定到其他程序上时被调用,而这个IBinder对象和之前看到的onServiceConnected方法中传入的那个IBinder是同一个东西。应用和Service间就依靠这个IBinder对象进行通信。
启动后的界面如下图:

  相关解决方案