今天复习了一下IntentService的源码,在这里记录一下
先上源码
package android.app;
import android.annotation.WorkerThread;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
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) {
//标记2
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
public IntentService(String name) {
super();
mName = name;
}
@Override
public void onCreate() {
super.onCreate();
//标记1
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@WorkerThread
protected abstract void onHandleIntent(Intent intent);
}
然后来讲解一下:
- IntentService里有一个自定义的Handler类,名字叫ServiceHandler,这个ServiceHandler是执行异步任务的,为什么它可以执行异步任务呢,看标记1,因为我们给这个ServiceHandler设置的Loop是HandlerThread的Loop,而HandlerThread是在新线程创建的Loop,所以我们这个ServiceHandler可以且仅可以执行异步任务
- IntentService启动以后,在onStart方法里可以看到会发送一个Message到HandlerThread的Looper,因为Looper是从HandlerThread取到的所以这个Looper在新线程,所以ServiceHandler的handleMessage也是在新线程执行的,然后调用IntentService的抽象方法onHandleIntent,很明显onHandleIntent方法里不能直接操作UI元素,因为该方法不是执行在UI线程
再说一下HandlerThread,先放源码:
package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
@NonNull
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
}
HandlerThread是继承的Thread,在HandlerThread中有一个Loop类属性,这个Loop会在HandlerThread的run方法中创建,注意到里面有一个notifyAll方法,为什么有这个方法呢,是因为HandlerThread还有一个getLooper方法,这个方法在IntentService的onCreate方法里被调用了,用来将HandlerThread的Loop传递给IntentService的ServiceHandler,但是因为Loop的创建是在run方法里,所以调用HandlerThread的getLooper方法时Loop不一定实例化了,所以getLooper方法里判断线程正在执行并且Loop为null的时候执行wait方法,等待HandlerThread的run方法实例化了Loop以后调用notifyAll唤醒等待返回实例化了的Loop实例
流程就是这样的,还有一些细节,如:
- 停止IntentService的时候,onDestory会立即执行,后续任务不会继续,看IntentService的onDestory也能看出来,方法里的mServiceLooper.quit();这句话清空了任务,但是正在执行的任务不会被打断。
- 在IntentService的ServiceHandler类的handleMessage方法里,为什么执行了stopSelf(msg.arg1);却不会把当前任务的后续任务都停止了呢?是因为IntentService会尝试通过stopSelf(int startId)来尝试停止服务。之所以不用stopSelf()来停止服务,是因为stopSelf()会立刻停止服务,而stopSelf(int startId)则会等待所有的消息都处理完毕才回终止服务。一般来说,stopSelf(int startId)在尝试停止服务之前会判断最近启动服务的次数是否和startId相等,如果相等则立刻停止服务。这些是文档里说的,源码我还没看,有兴趣可以自己看看。
- 细心的朋友应该注意到IntentService中的2个属性
加了volatile,这个关键字的作用是什么呢,这就涉及到JVM的执行方式了,JVM虚拟机可能会给语句做优化,虽然你语句写的顺序是A然后B,但是JVM可能给你优化成先执行B语句再执行A语句,这样的话下面的代码private volatile Looper mServiceLooper; private volatile ServiceHandler mServiceHandler;
可能就有问题,因为JVM可能给你优化成先执行语句2再执行语句1,这样会导致什么后果呢,如果先执行语句2的话,mServiceLooper是null,因为mServiceLooper = thread.getLooper();还没有执行,所以ServiceHandler传参进去的是个null,然后再执行语句1已经没有意义了,因为ServiceHandler已经传进去一个null参数了。而加上volatile能保证这2个语句在任何JVM里都能保证执行顺序先语句1后语句2。在IBM的官网有这部分的讲解,可以自己再深入了解一下mServiceLooper = thread.getLooper();//语句1 mServiceHandler = new ServiceHandler(mServiceLooper);//语句2
- 为什么不建议通过 bindService() 启动 IntentService?因为IntentService 源码中的 onBind() 默认返回 null;不适合 bindService() 启动服务,如果你执意要 bindService() 来启动 IntentService,可能因为你想通过 Binder 或 Messenger 使IntentService 和 Activity 可以通信,这样的话 onHandleIntent() 不会被回调,因为相当于在你使用 Service 而不是 IntentService。