Service生命周期和启动方法以及IntentService

来源:互联网 发布:社交数据包括什么 编辑:程序博客网 时间:2024/06/01 07:35

通过StartService启动Service,当访问者退出时,Service仍然能运行,访问者与Service之间没有关联。而bindService,访问者与服务绑定,访问者一旦退出,服务也终止。


用StartService()启动,StopService()停止服务

onCreate():在服务创建时调用

onStartCommande():在每次服务启动时调用(会被多次调用,但只有一个Service实例)

onDestroy():服务被销毁时调用,用于回收不再使用的资源

注意:如果想让服务自己停止,要调用stopSelf()



用bindService()绑定,unbindService()解除绑定

bindService(Intent i,ServiceConnectionconn,int flags); ServiceConnection对象用于监听访问者和服务之间的连接情况,当连接成功时将回调该对象的onServiceConnected(ComponentName name,IBinderbind);当Service的宿主由于某种原因异常终止时,会调用该对象的onServiceDisconnected(ComponentName name)方法。

注意:当调用者通过unbindService接触绑定时,并不会调用onServiceDisconnected。

Service内有唯一一个抽象方法onBind(),自定义服务时必须实现它。这个方法可以让服务与活动联系更紧密,因为这个方法返回了一个IBinder对象,这个IBinder会传给上面onServiceConnected方法中的IBinder,这样访问者可以通过IBinder与服务进行通信。(IBinder相当于Service组件内部的钩子)

比如我们在MyService中提供一个下载功能,然后由活动决定何时开始下载以及随时查看下载进度。

public class BindService extends Service{private MyBinder binder=new MyBinder();//内部类MyBinderpublic class MyBinder extends Binder//继承Binder类实现了一个IBinder对象(Binder是IBinder的实现类){public int getCount()<span style="white-space:pre"></span>return 1;}@Overridepublic IBinder onBinder(Intent i)<span style="white-space:pre"></span>return binder;@Overridepublic void onCreate(){}>@Overridepublic boolean onUnbind(Intent i)<span style="white-space:pre"></span>return true;//@Overridepublic void onDestroy(){}}

public class MainActivity extends Activity{BindService.MyBinder binder;//保持所启动的Service的IBinder对象private ServiceConnection conn=new ServiceConnection(){@Overridepublic void onServiceConnected(ComponentName name,IBinder bind){binder=(BindService.MyBinder) bind;}@Overridepublic void onServiceDisconnected(ComponentName name){}}@Overridepublic void onCreate(Bundle savaedInstanceState){final Intent intent=new Intent(this,BindService.class);bindService(intent,conn,Service.BIND_AUTO_CREATE);//flags,如果没有Service则自动创建一个<span style="white-space:pre"></span>int c=bind.getCount();}}
bindService之后,先调用Service的onCreate(),然后调用onBind(),onBind()返回一个IBinder对象,然后调用onServiceConnected()


生命周期:

onCreate():

onBind():不管连接了多少次,onBind只执行一次

onUnbind():被绑定的生命周期必须由访问者调用unBindService()才会解除绑定

onDestroy():


注意

还有一种特殊情况。如果活动a用StartService启动了某服务:onCreate() ---> onStartCommand(),这时活动b用bindService()绑定该服务,之后解绑:onBind() ---> onServiceConnected() ---> onUnBind();然后又调用bindService再次绑定:onRebind()。能回调onRebind的前提除了服务需要由statService启动以外还需要onBind方法中返回true。我们还发现,这种同时用了start和bind的情况下,只unBindService,不会调用onDestroy,即服务不会终止。必须同时满足stop和unBind,服务才会终止。





IntentService

Service存在的两个问题
1.Service中的代码都是默认运行在主线程当中的,不会单独启动一条新线程,所以如果在服务中处理一些耗时任务,会产生ANR。
2.Service不会专门启动一个进程,而是与它所在的应用位于同一个进程
3.不能同时处理多个请求

对于第1点,我们可以使用多线程编程,在服务的onStartCommand方法或是BindService类的onCreate方法中中开启一个子线程去处理耗时任务,如果想要线程的任务执行完就停止服务,可以在run()的最后(任务处理完成后)调用stopSelf(),而IntentService就直接为我们创建了子线程执行耗时任务,处理异步请求的时候不需要自己去开启新的线程,可以减少写代码的工作量。

源码分析

这是一个基于消息循环的服务,每次启动该服务并不是马上处理你的任务,而是首先会创建新的线程和对应的Looper,Handler,并且在MessageQueue中添加Message对象,当Looper发现有Message的时候调用Handler的handleMessage()方法,然后在onHandleIntent((Intent)msg.obj)中调用你的处理程序。处理完后即会停止自己的服务。 
public abstract class IntentService extends Service {         private volatile Looper mServiceLooper;         private volatile ServiceHandler mServiceHandler;         private String mName;         private boolean mRedelivery;         private final class ServiceHandler extends Handler {                 public ServiceHandler(Looper looper) {                         super(looper);                 }                 @Override                 public void handleMessage(Message msg) {                         onHandleIntent((Intent)msg.obj);                         stopSelf(msg.arg1);                 }         }</span>
这里面有一个Looper对象,用来在新的线程中启动一个消息循环,来检查是否有新的任务需要执行,ServiceHander最终会与这个Looper绑定,通过这个Handler向Looper发送消息。

构造函数:必须传入一个name,因为工作线程的构造函数需要一个名称
public IntentService(String name) {          super();          mName = name;  } 

@Override         public void onCreate() {                 super.onCreate();                 HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");                 thread.start();                 mServiceLooper = thread.getLooper();                 mServiceHandler = new ServiceHandler(mServiceLooper);         }

 IntentService创建时就会创建并启动Handler线程(HandlerThread),然后再将Handler对象与此线程的Looper对象绑定。并把Looper对象mServiceLooper传给ServiceHandler

在IntentService的startCommand()方法中直接调用了onStart(),我们直接看onStart()的源码:

@Override         public void onStart(Intent intent, int startId) {                 Message msg = mServiceHandler.obtainMessage();                 msg.arg1 = startId;                 msg.obj = intent;                 mServiceHandler.sendMessage(msg);         }
当调用startService的时候,就会产生一条附带startId和Intent的Message并发送到MessageQueue中,接下来Looper发现MessageQueue中有Message的时候,就会通知Handler调用handleMessage()处理消息,代码如下
@Override         public void handleMessage(Message msg) {                         onHandleIntent((Intent)msg.obj);                         stopSelf(msg.arg1);         }
handleMessage()中调用了 onHandleIntent((Intent)msg.obj),这是一个抽象的方法,我们需要重写这个方法,在方法中处理我们的任务。当任务完成时就会调用stopSelf()结束这个Service。



IntentService有以下特点:

(1)  它创建了一个独立的工作线程来处理所有的通过onStartCommand()传递给服务的intents。

(2)  创建了一个工作队列,来逐个发送intent给onHandleIntent()。

(3)  不需要主动调用stopSelft()来结束服务。因为,在所有的intent被处理完后,系统会自动关闭服务。

(4)  默认实现的onBind()返回null

(5)  默认实现的onStartCommand()的目的是将intent插入到工作队列中

在IntentService中有一个队列的概念,即在第一次启动IntentService,并在onHandleIntent中执行的时候,再第二次次启动IntentService,第二次的操作不会立刻执行,而是先将其放在队列中,当第一次运行完时,再执行第二次操作。这与Service是不一样的,当第一次还未执行完时,启动第二次,他会直接从onStartCommand开始执行。而不是像第一次一样按循序执行。 


使用IntentService的好处:

会创建单独的线程处理onHandleIntent()方法,开发者不用处理多线程的问题;

onHandleIntent()执行完成后会自动调用stopSelf(),开发者不用自己调用;

为Service的onBind方法提供了默认实现(默认返回null),即不用重写onBind;

为onStartCommand提供了默认实现,即不用重写onStartCommand,该实现会将请求Intent添加到队列中。

只用重写onHandleIntent即可。例子:
public class MyIntentService extends IntentService {final static String TAG="vic";public MyIntentService() {super("");}@Overrideprotected void onHandleIntent(Intent arg0) {//只用重写onHandleIntent这个抽象方法Log.i(TAG,"begin onHandleIntent()");try {Thread.sleep(5*1000);<span style="white-space:pre"></span>//执行耗时任务} catch (InterruptedException e) {e.printStackTrace();}Log.i(TAG,"end onHandleIntent()");}}
启动这个IntentService的代码:
Intent intent=new Intent(this,MyIntentService.class);startService(intent);
注意:自定义的IntentService构造函数是必需要有,而且必须调用IntentService(字符串) ,因为工作线程的构造函数必须使用一个名称。

注意:IntentService构造函数是必需要有,而且必须调用IntentService(字符串) ,因为工作线程的构造函数必须使用一个名称。
0 0
原创粉丝点击