1.为什么要使用IntentService?
前提条件是你想使用Service同时又想在Service做一些耗时操作或异步任务处理,这时,使用IntentService比较合适,相较于Service,你不用在Service中重新创建线程,同时你也不用考虑不使用它的时候去调用stopService()方法,下面会讲到这一点。
2.IntentService的定义
* IntentService is a base class for {@link Service}s that handle asynchronous
* requests (expressed as {@link Intent}s) on demand. Clients send requests
* through {@link android.content.Context#startService(Intent)} calls; the
* service is started as needed, handles each Intent in turn using a worker
* thread, and stops itself when it runs out of work.
上面文字的大意就是,IntentService是Service类根据需要处理异步请求(通常用Intent表示)的基类。客户端通过Context的startService(Intent)方法来发送请求。Service根据需要启动,它是通过一个工作线程并按照顺序来处理每个Intent,当执行完所有任务后会stop self(通过调用stopSelf()方法终止服务)。
3.IntentService源码分析
在开始分析源码之前,简单的总结一下我理解的IntentSercice:IntentSercie就是一个可以处理异步任务的Service,内部维护了自己的ServiceHandler和HandlerThread用于消息的传递,并在处理任务结束后自动结束自己的生命周期。
下面我们开始分析它的源码(package android.app;)
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
@UnsupportedAppUsage
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);
}
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
/**
* Sets intent redelivery preferences. Usually called from the constructor
* with your preferred semantics.
*
* <p>If enabled is true,
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_REDELIVER_INTENT}, so if this process dies before
* {@link #onHandleIntent(Intent)} returns, the process will be restarted
* and the intent redelivered. If multiple Intents have been sent, only
* the most recent one is guaranteed to be redelivered.
*
* <p>If enabled is false (the default),
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
* dies along with it.
*/
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
/**
* Unless you provide binding for your service, you don't need to implement this
* method, because the default implementation returns null.
* @see android.app.Service#onBind
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
* When all requests have been handled, the IntentService stops itself,
* so you should not call {@link #stopSelf}.
*
* @param intent The value passed to {@link
* android.content.Context#startService(Intent)}.
* This may be null if the service is being restarted after
* its process has gone away; see
* {@link android.app.Service#onStartCommand}
* for details.
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
IntentService的启动方式和Service是一样的,通常我们使用startService(intent)来启动它。启动IntentService,会依次执行onCreate()->onStartCommand()->onStart()(onStart方法在Service中已经标记为弃用,IntentService重写了该方法,并在onStartCommand中被调用)方法。
首先我们看下OnCreate()方法源码
可以看到,服务启动后,首先做了一些对于IntentService来说初始化的工作,IntentService之所以可以用来处理异步任务就是由于它内部的ServiceHandler和HandlerThread。上面的代码首先实例化了一个HandlerThread线程(源码这里暂不赘述,有兴趣的话可以看看我的另外一篇文章记录-HandlerThread源码分析
,并通过start()方法来启动该线程。之后通过thread获取到该线程的Looper对象来实例化一个ServiceHandler。
然后我们再看onStartCommand()方法源码
注释的大意是:你不应该在你的IntentService中重写该方法,相反,应该在你自己定义的IntentService中重写onHandleIntent()方法,onHandleIntent方法会在收到启动请求时由系统调用。可以看到该方法中调用了onStart()方法,并且把intent,startId传递过去。
接着看onStart()方法
image.png
在onStart方法中,通过我们在onCreate()中实例化的ServiceHandler对象在消息池中获取一个消息对象,并把该对象设置给message的target属性(感兴趣的可以看下,通过这种方法生成message可以复用消息池中的对象而不必新建,同时又可以直接把handler对象赋值给message的target属性,在Looper.loop()方法中会用到,此处不赘述),然后通过mServiceHandler的sendMessage方法发送消息。
接下来我们看ServiceHandler的源码
可以看到handler在收到消息后,做了两件事儿,第一,调用onHandleIntent方法,该方法在IntentService中是一个抽象方法,需要我们的子类自己实现,我们可以在该方法中做一些耗时操作(不必另外开启线程,因为当前该方法就是在上面讲到的HandlerThread中执行的);第二,在执行完onHandleIntent()方法后,IntentService调用了自己的stopSelf()方法来结束自己的生命周期。stopSelf()方法和我们在activity中调用stopService方法一样,都会触发Service的OnDestroy()方法。大家可能注意到,stopSelf方法有个startId的参数,需要注意的是startId必须配对,stopSelf()才会停止服务。
4.常见问题
4.1可以在onHandleIntent()方法中进行异步操作吗?
onHandleIntent()方法本身就是在子线程中执行的,如果在此方法中再执行异步任务,由于onHandleIntent执行完成之后会调用stopSelf()方法,此方法会结束掉当前的IntentService,同时在IntentService的onDestroy方法中mServiceHandler会执行quit()方法,所以导致异步代码的结果无法接收到。
4.2.可以使用bindService()来启动IntentService吗?
image这是一张Service在不同启动方式下的生命周期图,我们可以看到通过bindService()来启动并不会调用onStartCommand()方法,IntentService中维护的mServiceHandler也就无法发送消息进而onHandleIntent()方法也不会再调用,所以也就和使用普通的Service没有区别了。
4.3.多次启动IntentService会发发生什么?停止服务后,后续的事件还会不会执行?
mServiceHandler是在onCreate中创建的,在Service中,无论是何种启动方式,此方法在整个生命周期中只会执行一次,所以,HandlerThread和ServiceHandler都只实例化了一次,相反,每次启动都会调用onStartCommand()方法,然后把消息加入到消息队列中进行等待并按顺序执行。问题5中已经说到,停止服务后在onDestroy方法中会调用mServiceHandler的quit()方法,导致后续事件无法执行。
网友评论