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

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


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

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

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

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

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



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

bindService(Intent i,ServiceConnection conn,int flags); ServiceConnection对象用于监听访问者和服务之间的连接情况,当连接成功时将回调该对象的onServiceConnected(ComponentName name,IBinder bind);当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();
//内部类MyBinder
public class MyBinder extends Binder//继承Binder类实现了一个IBinder对象(Binder是IBinder的实现类)
{
public int getCount()	return 1;
}

@Override
public IBinder onBinder(Intent i)	return binder;

@Override
public void onCreate(){}

>@Override
public boolean onUnbind(Intent i)	return true;//

@Override
public void onDestroy(){}
}

public class MainActivity extends Activity
{
	BindService.MyBinder binder;//保持所启动的Service的IBinder对象
	private ServiceConnection conn=new ServiceConnection(){

		@Override
		public void onServiceConnected(ComponentName name,IBinder bind){
			binder=(BindService.MyBinder) bind;
		}
		@Override
		public void onServiceDisconnected(ComponentName name){}
	}

	@Override
	public void onCreate(Bundle savaedInstanceState){
		final Intent intent=new Intent(this,BindService.class);
		bindService(intent,conn,Service.BIND_AUTO_CREATE);//flags,如果没有Service则自动创建一个
		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); 
                } 

        }
这里面有一个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("");
}
@Override
protected void onHandleIntent(Intent arg0) {//只用重写onHandleIntent这个抽象方法
Log.i(TAG,"begin onHandleIntent()");
try {
Thread.sleep(5*1000);	//执行耗时任务
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG,"end onHandleIntent()");
}
}
启动这个IntentService的代码:
Intent intent=new Intent(this,MyIntentService.class);
startService(intent);
注意 :自定义的IntentService构造函数是必需要有,而且必须调用IntentService(字符串) ,因为工作线程的构造函数必须使用一个名称。

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

你可能感兴趣的:(进击的兔子之Android基础)