IntentService和HandlerThread源码分析

1,060 阅读7分钟
原文链接: blog.csdn.net

版权声明:本文为博主原创文章,欢迎大家转载!

转载请标明出处: blog.csdn.net/guiying712/…,本文出自:【张华洋的博客】


在这篇文章中我将介绍 在 Android 中的 IntentService,在分析 IntentService的原理时,将顺便分析 IntentService中使用到的 HandlerThread 。

IntentService

IntentService 继承于Android四大组件中的 Service, 而 IntentService 与 Service 的区别在于它可以处理异步请求,我们都知道 Service 中的代码都是默认运行在主线程当中的,如果直接在 Service 中去处理耗时的任务,就很容易出现 ANR的 情况,而 IntentService 则是直接在子线程中工作的。另外当我们使用 startService(Intent) 方法 启动 IntentService 后,IntentService 就会在 工作线程中处理每一个 Intent ,并且在完成这些任务后停止它自己

还是老规矩,分析源码之前,先看下怎么使用 IntentService:

public class MyIntentService extends IntentService {

    public MyIntentService() {
        super("MyIntentService"); // 必须调用父类的有参构造函数
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // 打印当前线程的名称,证明是在子线程中
        Log.d("MyIntentService", "Thread id is " +  Thread.currentThread().getName());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 为了证明IntentService在处理完工作后停止了自己
        Log.d("MyIntentService", "onDestroy");
    }

}

可以看,使用 IntentService 真的是非常简单,我们只需要继承 IntentService ,并提供一个构造函数,并且必须在其内部调用父类的有参构造函数,然后重写 onHandleIntent(Intent intent)方法,在 onHandleIntent 方法中可以去处理一些具体的业务逻辑,而且不用担心ANR的问题,因为这个方法已经是在子线程中运行了。

接下来我们看下 IntentService 的源码:

public class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;

    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);
        }
    }

    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);

     /**
     * 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;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //创建一个HandlerThread的对象
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();//创建HandlerThread对象后就调用start()方法开启线程

        //获取HandlerThread中创建的 Looper
        mServiceLooper = thread.getLooper();
        //使用这个 Looper创建一个 Handler
        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);
    }

  @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }
}

从源码中,我们可以看到之所以在 MyIntentService的构造函数中必须在调用父类的有参构造函数,是因为IntentService需要为它的工作线程起一个名字,用于我们debug的时候区分。这个我们可以在 onCreate()方法中的这段代码得到印证:

HandlerThread thread = new HandlerThread(“IntentService[” + mName + “]”); // mName 就是我们在构造函数中传入的参数

当我们通过 startService(Context, Intent) 方法启动 IntentService 后,就会回调 IntentService 的 onCreate 和 onStart 方法:

1、首先在回调onCreate()方法中 创建一个 HandlerThread,并开启这个线程,然后获取HandlerThread中创建的 Looper ,使用这个 Looper创建一个 ServiceHandler 。

2、接着就会回调 onStart(@Nullable Intent intent, int startId) 方法,我们可以看到在 onStart 方法中,会通过 ServiceHandler 拿到一个Message,并使Message携带我们的请求参数,然后通过 ServiceHandler 将这个Message发送出去。如果有不懂 Handler 工作原理的可以查看这篇文章:Android Handler源码解析

3、ServiceHandler 发送的 Message 最终会被分发到 IntentService 的内部类 ServiceHandler 的 handleMessage(Message msg) 方法中。在这里就会调用 IntentService 的抽象方法 onHandleIntent(@Nullable Intent intent),并且这个方法上有个注解:@WorkerThread,代表这个方法是在工作线程中被调用。然后就会调用 Service 的 stopSelf 方法 停止这个服务,因此你无需调用 stopSelf 方法。

4、一旦 IntentService 调用了 stopSelf 方法后,就会回调 onDestroy() 方法, 我们在 HandlerThread 中创建的 Looper 就会退出循环。

另外在使用 IntentService 时需要注意以下事项 :

1、在使用 IntentService 时,不要重写 onStartCommand 方法,而是应该重写 onHandleIntent 方法,当 IntentService 被 start 后,系统回调的是 onHandleIntent 。

2、不要在 你的 IntentService 中提供 Service 的 onBind 方法,你不需要实现这个方法,因为 IntentService 默认实现了这个方法并返回 null 。

HandlerThread

说起 IntentService 就不得不讲讲 HandlerThread,HandlerThread 可以说是Android中应用非常广泛的一个类,它继承自 Thread,用于开启一个自带 Looper 的 新线程,这个新线程中创建的 Looper 可以用来创建 Handler类,因此 HandlerThread 经常与 Handler 搭配使用,这也是类名为什么称为HandlerThread 的原因。

注意 :Thread类 的 start() 方法仍然需要调用。

我们在 IntentService 中已经看到 HandlerThread是如何 Handler搭配使用的,因此这里我们就直接查看HandlerThread的源码 :

public class HandlerThread extends Thread {
    Looper mLooper;
    private @Nullable Handler mHandler;

    protected void onLooperPrepared() {
    }

    @Override
    public void run() {
        ...
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        ...
        onLooperPrepared();
        Looper.loop();
        ...
    }

    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;
    }

    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
}

在分析HandlerThread 的源码之前,我们先复习下Java的线程。

在 Java 中每个线程都是通过某个特定Thread对象所对应的方法 run() 来完成其操作的,方法 run() 称为线程体,它包含了要执行的这个线程的内容。我们通过调用Thread类的 start() 方法来就可以启动一个线程,一旦调用 start() 后,线程就会被放到等待队列,等待CPU调度,但并不一定要马上开始执行,只是将这个线程置于可动行状态。

在Java当中,线程通常有五种状态:创建、就绪、运行、阻塞和死亡:

第一是创建状态。生成线程对象,并没有调用该对象的start方法,这时线程处于创建状态。
  
第二是就绪状态。当调用了线程对象的 start 方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态。
  
第三是运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行 run 函数当中的代码。
 
第四是阻塞状态。线程正在运行的时候被暂停,通常是为了等待某个事件的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
  
第五是死亡状态。如果一个线程的 run 方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用 start 方法令其进入就绪。

在 HandlerThread 的 run() 方法中,先调用 Looper.prepare() 在当前线程创建一个 Looper ,然后通过 Looper.myLooper() 获取到这个 Looper ,接下来执行了 onLooperPrepared() 方法,如果我们需要在 Looper进入无限循环之前执行一些设置,我们就可以重写这个方法。之后便调用Looper.loop() 使 Looper开始运行。

接着我们在看下 HandlerThread 的 getLooper() 方法,这个方法会返回与当前线程关联的 Looper(就是在 run() 中创建 的 Looper),如果这个线程还没有启动(这也是为什么我们创建 HandlerThread 后就要调用 start() 方法的原因),或者一些原因导致 Thread的 isAlive()返回 false,就会导致 getLooper() 返回 null。如果这个线程已经启动了, getLooper() 就会一直阻塞,直到 Looper 初始化完成。

我们注意到,在 HandlerThread 中也提供了 quit() 方法 用于退出 HandlerThread 的 Looper ,由于 IntentService 在销毁时会主动调用 looper.quit() 方法使 Looper 退出,所以如果你在使用完 HandlerThread 后也需要主动调用 quit() 方法。