IntentService和HandlerThread源码分析


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

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


在这篇文章中我将介绍 在 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 就不得不讲讲 HandlerThreadHandlerThread可以说是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 方法令其进入就绪。

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

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

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

猜你喜欢

转载自blog.csdn.net/guiying712/article/details/79301446