android基础知识05:四大组件之service 01

本文主要介绍service相关内容。包括两篇文章:

android基础知识05:四大组件之service 01

android基础知识05:四大组件之service 02:远程调用

android基础知识05:四大组件之service 03:实现机制


本文资料来源于网络,参考了最牛网中关于android service的相关分析。

实例程序地址:http://download.csdn.net/detail/xianming01/4131098

http://download.csdn.net/detail/xianming01/4131146

1、什么是service

Service,看名字就知道跟正常理解的“服务”差不多,后台运行,可交互这样的一个东西。它跟Activity的级别差不多,但是他不能自己运行,需要通过某一个Activity或者其他Context对象来调用, Context.startService() 和 Context.bindService()。
两种启动Service的方式有所不同。这里要说明一下的是如果你在Service的onCreate或者onStart做一些很耗时间的事情,最好在Service里启动一个线程来完成,因为Service是跑在主线程中,会影响到你的UI操作或者阻塞主线程中的其他事情。
什么时候需要Service呢?比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务嘛,总是藏在后头的。

Service是在一段不定的时间运行在后台,不和用户交互应用组件。每个Service必须在manifest中 通过<service>来声明。可以通过contect.startservice和contect.bindserverice来启动。
Service和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现。
service的两种模式(startService()/bindService()不是完全分离的):
1)本地服务 Local Service 用于应用程序内部。
它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,你只需要调用一次stopService()来停止服务。
用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
2)远程服务 Remote Service 用于android系统内部的应用程序之间。
它可以通过自己定义并暴露出来的接口进行程序操作。客户端建立一个到服务对象的连接,并通过那个连接来调用服务。连接以调用Context.bindService()方法建立,以调用 Context.unbindService()关闭。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。
可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。

2、本地服务

2.1 startservice方式

Service的启动方式一:
启动:Context.startService(new Intent(context,xxx.class));
停止:Context.stopService() ;
我画了一个Service启动的流程图,相信大家一看就懂。Activity通过Intent启动Service,如果Service还没有运行,则android先调用onCreate()然后调用onStart();如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。 调用stopService就会触发Service的onDestroy()方法。 图片点击放大~

android基础知识05:四大组件之service 01

我们先来介绍一下本地服务的例子。

2.1.1 界面

android基础知识05:四大组件之service 01

其中可以播放音乐、暂停、停止等。同时点击finish键可以关闭应用(但服务不关闭,音乐可以继续播放),点击exit推出 应用,同时关闭服务。

2.1.2 音乐播放

/** * ClassName:MyMediaController * Function: Mediaplayer 的一个控制类,控制播放器的播放 暂停 停止 等动作 * REASON * * @author Leon * @version * @since Ver 1.1 * @Date 2011-5-16 */ public enum MyMediaController implements Serializable { play { @Override public void execute() { if (mediaPlayer != null && !mediaPlayer.isPlaying()) mediaPlayer.start(); // TODO Auto-generated method stub } }, pause { @Override public void execute() { // TODO Auto-generated method stub if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.pause(); } } }, stop { @Override public void execute() { // TODO Auto-generated method stub if (mediaPlayer != null) { mediaPlayer.stop(); try { // 在stop后如果要重新Start需要prepare一下 mediaPlayer.prepare(); // 从头播放 mediaPlayer.seekTo(0); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; public static MediaPlayer mediaPlayer; public abstract void execute(); }2.1.3 service

/** * ClassName:MusicService * Function: TODO ADD FUNCTION * Reason: TODO ADD REASON * * @author Leon * @version * @since Ver 1.1 * @Date 2011-5-15 */ public class MusicService extends Service{ private String TAG = MusicService.class.getSimpleName(); private MediaPlayer myMediaPlayer ; public static final String INTENT_KEY= "action" ; @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { // TODO Auto-generated method stub Log.v(TAG , TAG+ " onCreate()"); super.onCreate(); if(myMediaPlayer==null){ myMediaPlayer=MediaPlayer.create(this, R.raw.test) ; myMediaPlayer.setLooping(false); } } @Override public void onStart(Intent intent, int startId) { // TODO Auto-generated method stub Log.v(TAG , TAG + " onStart()"); super.onStart(intent, startId); if(intent!=null){ MyMediaController mediaControl =(MyMediaController)intent.getSerializableExtra(MusicService.INTENT_KEY); mediaControl.mediaPlayer=myMediaPlayer; mediaControl.execute(); } } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.v(TAG , " onDestroy"); if(myMediaPlayer!=null){ myMediaPlayer.stop(); myMediaPlayer.release(); } } }2.1.4 界面

public class ServiceTestServerActivity extends Activity implements OnClickListener{ /** Called when the activity is first created. */ private static final String TAG = ServiceTestServerActivity.class.getSimpleName(); private TextView m_TextView_text; private Button btnPlay; private Button btnPause; private Button btnStop; private Button btnFinish; private Button btnExit; Intent intent; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); m_TextView_text= (TextView)findViewById(R.id.text); btnPlay= (Button)findViewById(R.id.play); btnPause= (Button)findViewById(R.id.pause); btnStop= (Button)findViewById(R.id.stop); btnFinish= (Button)findViewById(R.id.finish); btnExit= (Button)findViewById(R.id.exit); btnPlay.setOnClickListener(this); btnPause.setOnClickListener(this); btnStop.setOnClickListener(this); btnFinish.setOnClickListener(this); btnExit.setOnClickListener(this); intent=new Intent("xuxm.demo.service01.MusicService"); } private void playAction(MyMediaController playType) { Bundle bundle = new Bundle(); bundle.putSerializable(MusicService.INTENT_KEY, playType); intent.putExtras(bundle); ServiceTestServerActivity.this.startService(intent); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch(v.getId()) { case R.id.play: playAction(MyMediaController.play); m_TextView_text.setText(R.string.play); Log.d(TAG, "play......."); break; case R.id.pause: playAction(MyMediaController.pause); m_TextView_text.setText(R.string.pause); Log.d(TAG, "pause......."); break; case R.id.stop: playAction(MyMediaController.stop); m_TextView_text.setText(R.string.stop); Log.d(TAG, "stop......."); break; case R.id.finish: Log.d(TAG, "close......."); this.finish(); break; case R.id.exit: Log.d(TAG, "exit......."); stopService(intent); this.finish(); break; default: } } } 程序还是蛮简单的,所以不分析了。

运行时可以发现第一次startService时,会调用onCreate和onStart,在没有stopService前,无论点击多少次startService,都只会调用onStart。而stopService时调用onDestroy。再次点击stopService,会发现不会进入service的生命周期的,即不会再调用onCreate,onStart和onDestroy。
而onBind在startService/stopService中没有调用。

2.1 bind service方式
第二种是通过绑定的方式来启动Service。先看流程图,点击放大。

android基础知识05:四大组件之service 01

在这里我们使用了this.bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE); 来启动Service,当Service创建了同时绑定了之后,会回调我们定义的ServiceConnection(),从而传回IBinder接口,我们就能够调用Service中的方法了。这时候Activity就和Service实现了绑定,Activity退出了Service就相应的退出了。

<service android:name=".MusicService02" > <intent-filter > <action android:name="xuxm.demo.service02.MusicService" /> </intent-filter> </service>主要代码如下:

MusicService02

public class MusicService02 extends Service{ private String TAG = MusicService02.class.getSimpleName(); private MediaPlayer myMediaPlayer ; public static final String INTENT_KEY= "action" ; @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub Log.v(TAG, TAG+" onBind"); return mbinder; } LocalBinder mbinder=new LocalBinder(); public class LocalBinder extends Binder { MusicService02 getService() { return MusicService02.this; } } @Override public void onCreate() { // TODO Auto-generated method stub Log.v(TAG , TAG+ " onCreate()"); super.onCreate(); if(myMediaPlayer==null){ myMediaPlayer=MediaPlayer.create(this, R.raw.test) ; myMediaPlayer.setLooping(false); } } @Override public void onStart(Intent intent, int startId) { // TODO Auto-generated method stub Log.v(TAG , TAG + " onStart()"); super.onStart(intent, startId); } @Override public boolean onUnbind(Intent intent) { // TODO Auto-generated method stub Log.v(TAG , TAG +" onUnbind ,成功没有?" + super.onUnbind(intent)); return true; //return false; } @Override public void onRebind(Intent intent) { // TODO Auto-generated method stub Log.v(TAG , TAG +" onRebind()----------------------------------->"); super.onRebind(intent); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.v(TAG , " onDestroy"); if(myMediaPlayer!=null){ myMediaPlayer.stop(); myMediaPlayer.release(); } } public MediaPlayer getMyMediaPlayer() { return myMediaPlayer; } public void setMyMediaPlayer(MediaPlayer myMediaPlayer) { this.myMediaPlayer = myMediaPlayer; } }ServiceTestServerActivity

public class ServiceTestServerActivity extends Activity implements OnClickListener{ /** Called when the activity is first created. */ private static final String TAG = ServiceTestServerActivity.class.getSimpleName(); private TextView m_TextView_text; private Button btnPlay; private Button btnPause; private Button btnStop; private Button btnUnbind; private Button btnFinish; private Button btnExit; private MusicService02 bindMusicService; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); m_TextView_text= (TextView)findViewById(R.id.text); btnPlay= (Button)findViewById(R.id.play); btnPause= (Button)findViewById(R.id.pause); btnStop= (Button)findViewById(R.id.stop); btnFinish= (Button)findViewById(R.id.finish); btnExit= (Button)findViewById(R.id.exit); btnPlay.setOnClickListener(this); btnPause.setOnClickListener(this); btnStop.setOnClickListener(this); btnFinish.setOnClickListener(this); btnExit.setOnClickListener(this); connection(); } private void connection() { Log.v(TAG , TAG+"connection"); Intent intent = new Intent("xuxm.demo.service02.MusicService"); //this.startService(intent); this.bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch(v.getId()) { case R.id.play: MyMediaController.play.execute(); m_TextView_text.setText(R.string.play); Log.d(TAG, "play......."); break; case R.id.pause: MyMediaController.pause.execute(); m_TextView_text.setText(R.string.pause); Log.d(TAG, "pause......."); break; case R.id.stop: MyMediaController.stop.execute(); m_TextView_text.setText(R.string.stop); Log.d(TAG, "stop......."); break; case R.id.finish: Log.d(TAG, "close......."); this.finish(); break; case R.id.exit: Log.d(TAG, "exit......."); this.finish(); this.stopService(new Intent("xuxm.demo.service02.MusicService")); break; default: } } //调用bindService后 Service调用onBind()后 回调此函数 private ServiceConnection myServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder binder) { // This is called when the connection with the service has been // established, giving us the service object we can use to // interact with the service. Because we have bound to a explicit // service that we know is running in our own process, we can // cast its IBinder to a concrete class and directly access it. Log.v(TAG , TAG+ "onServiceConnected"); // TODO Auto-generated method stub bindMusicService = ((LocalBinder)binder).getService(); //给Controller设置Service初始化的MediaPlayer MyMediaController.mediaPlayer=bindMusicService.getMyMediaPlayer(); } @Override public void onServiceDisconnected(ComponentName name) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. // Because it is running in our same process, we should never // see this happen. // TODO Auto-generated method stub bindMusicService=null; Log.v(TAG, "..............onServiceDisconnected"); } }; //当Activity finish时必须解绑 不然会出现溢出 @Override public void finish() { // TODO Auto-generated method stub super.finish(); this.unbindService(myServiceConnection); } }

运行时,发现调用次序是这样的:
bindService:
1.MusicService02: onCreate
2.MusicService02: onBind
3.Activity: onServiceConnected
unbindService: 只是调用onDestroy
可见,onStart是不会被调用的,而onServiceDisconnected没有调用的原因在上面代码的注释有说明。

此时,activity停止时,service也停止了。

2.2 bind service的一些问题

前面的分析中可以看到Activity和Service,context.startService对应着Service中的onStart()方法,context.onBindService对应的是Service中的onBind()方法。当我们继想绑定一个Service又想在Activity停止时,Service不会停止,我们可以先StartService,然后再BindService()。这时候的流程图如下所示:

android基础知识05:四大组件之service 01

此时需要注意一个问题,当Activity退出的时候,Sercvice并不会停止,此时我们可以再进入Activity重新绑定,当这时候Service就会调用onRebind()方法,但是调用onRebind()方法的前提是先前的onUnbind()方法执行成功,但是使用super.onUnbind(intent)是执行不成功的,这时候我们要手动的使其返回true,再次绑定时Rebind()就会执行。否则,如果退出时不显示的指定onUnbind()为成功的话(为false),那么重新启动此Activity来绑定服务时,Service的onBind()方法和onReBind都不会执行,但是ServiceConnection方法确一定会回调了。这说明在Service中的onBind()方法不同于onStart()方法不能被重复调用。