Android从HandlerThread到IntentService的机制原理

768 阅读5分钟

IntentService的本质是一个带有HandlerThread worker线程的一个Service其特点是运行完之后自动停止,里面有个HandlerThread类型的成员变量,通过这个handler向worker线程发送消息,然后Service在工作线程中做耗时操作。说到这就有疑问了

  • Q1) HandlerThread是个什么东西,里面长什么样?怎么工作的?
  • Q2) Looper什么是怎么回事,怎么实现的?
  • Q3) 一直在提到Looper使用ThreadLocal存储的,那ThreadLocal到底是个什么东西呢?
  • Q4) 绕一圈终于回来了,那HandlerThread作为一种拥有Looper的Thread是如何在IntentService中发挥自己的光和热的呢?

看官莫急,接下来我们就详解分解。

1) HandlerThread

ThreadHandler其实就是一个带有Looper的Thread,所以在HandlerThread身上会有一个getLooper()方法。通过getLooper()方法获取线程的looper,使用这个Looper创建Handler,创建的handler可以向Looper发送Message了。另,此时Handler中的handlerMessage()方法就运行在这个worker线程中。

1.1) HandlerThread 中的run方法

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

可以看出在run()方法中做的主要工作是创建Looper,给成员变量mLooper赋值,调用Looper.loop()让Looper开始工作。而且给 mLooper = Looper.myLooper(); notifyAll();加了同步,为什么呢要看getLooper()方法;

1.2) HandlerThread中的getLooper()方法

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

getLooper方法中当mlloer为空的时候就会循环等待直到mLooper不为空才返回,这是防止当run()方法中还没有对mLooper进行赋值,导致获取的mlooper为空。

2) Looper

Looper 主要的功能内部维护这个一个存放Message的消息队列MessageQueue,把Looper和线程存在这绑定关系,一个Looper实例对应一个线程。循环读取消息队列Message中的Message交给Message的target也就是发送这个消息的handler中handler dispatchMessage()方法处理,从而实现线程通讯。

2.1) Looper里面的主要成员变量

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; 
final MessageQueue mQueue;
final Thread mThread;

2.2) Looper里面的主要方法

Looper.prepare();
Looper.looper();
Looper.myLooper();

2.3) prepare()

public static void prepare() {
       prepare(true);
  }
​
private static void prepare(boolean quitAllowed) {
   if (sThreadLocal.get() != null) {
       throw new RuntimeException("Only one Looper may be created per thread");
  }
    sThreadLocal.set(new Looper(quitAllowed));
  }
  • prepar()方法的主要作用就是初始化Looper,并把他存在ThreadLocal里面。
  • 每个线程只能创建一个Looper,如果已经创建过就会抛出异常。 Looper的初始化是用构造函数进行的如下
private Looper(boolean quitAllowed) {
       mQueue = new MessageQueue(quitAllowed);
       mThread = Thread.currentThread();
  }

2.4) Looper.myLooper();

  public static @Nullable Looper myLooper() {
       return sThreadLocal.get();
  }

见名知意,myLooper()方法很简单就是从ThreadLocal中获取Looper并返回。

2.5) Looper.looper();

looper()方法是从Looper中取出MessageQueue,然后循环读取message,交给message的target处理也就是发送这个消息的handler处理。

 public static void loop() {
       final Looper me = myLooper();
       final MessageQueue queue = me.mQueue;
       for (;;) {
           Message msg = queue.next(); // might block
           if (msg == null) {
               return;
          }
      }
           try {
               msg.target.dispatchMessage(msg);
          } finally {
               if (traceTag != 0) {
                   Trace.traceEnd(traceTag);
              }
          }
           msg.recycleUnchecked();
      }
  }

2.6) 一直先循环为什么不会卡死?

  • epoll模型当没有消息的时候会epoll.wait,等待句柄写的时候再唤醒,这个时候其实是阻塞的。
  • 消息,你的各种点击事件,所以就会有句柄写操作,唤醒上文的wait操作,所以不会被卡死了。

3) ThreadLocal

ThreadLocal类提供了如下几个方法

public T get() { }
public void set(T value) { }
public void remove() { }
protected T initialValue() { }

3.1) get()

  public T get() {
      Thread t = Thread.currentThread();
      ThreadLocalMap map = getMap(t);
      if (map != null) {
          ThreadLocalMap.Entry e = map.getEntry(this);
          if (e != null)
              return (T)e.value;
      }
      return setInitialValue();
  }
   
    private T setInitialValue() {
      T value = initialValue();
      Thread t = Thread.currentThread();
      ThreadLocalMap map = getMap(t);
      if (map != null)
          map.set(this, value);
      else
          createMap(t, value);
      return value;
  }
​
​
  • 第一句是取得当前线程,然后通过getMap(t)方法获取到一个map,map的类型为ThreadLocalMap。然后接着下面获取到<key,value>键值对,注意这里获取键值对传进去的是 this(也就是当前的ThreadLocal),而不是当前线程t。
  • 如果当前还没有通过set()方法设置value的时候会调用setInitialValue()方法设置并返回,值是通过initialValue()方法设置,如果没有设置,则默认返回null;

3.2) set()

public void set(T value) {
​
      Thread t = Thread.currentThread();
      ThreadLocalMap map = t.threadLocals;
       
      if (map != null)
          map.set(this, value);
      else
          createMap(t, value);
        
  }

一个线程中可能存在多个ThreadLoacl,因而在Thread里面维护着一个ThreadLocalMap,这个map键就是ThreadLocal,值就是我们存的值。

3.3) 移除ThreadLocal当前线程数据

public void remove() {
        ThreadLocalMap m = getMap(Thread.currentThread());
        if (m != null)
            m.remove(this);
    }

3.4) ThreadLocal 小结

使用ThreadLocal存储的数据,会为每个线程存储一份数据拷贝,比如线程A和线程B都要一个名字叫mData的数据存储在ThreadLocal中,各自存取互不影响。Looper使用ThreadLocal存储,不同的Thread线程对应着不同的Looper,假如每个程序猿都有女朋友,虽然都加女朋友(Looper)但是每个程序猿(Thread)获取的女朋友是不一样的,当然如果一样就麻烦了,不做讨论。

4) IntentService

4.1) 关于IntentService

IntentService里面开启一个worker线程,线程工作跑完之后自动关闭。 IntentService中有一个ServiceHandler内部类

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

其本质还是一个Handler,覆盖了Handler中的handlerMessage()方法,交给外面的onHandlerMessage处理。

4.2) onHandleIntent()

IntentService中onHandleIntent()方法运行在worker线程中。

@Override
  public void onCreate() {
  
      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);
  }
​
  • IntentService的onCreate()中创建的了HandlerThread并开始运行,从handlerThread中获取looper创建handler。
  • 在onstart()方法中像handler发送消息,最终消息在serviceHandler的OnHandlerIntent()方法中接受处理(处于woker线程)。

我们通过四个问题驱动了解了ThreadLocal、Looper、HandlerThread、IntentService。简单的说可以总结为:

  • IntentService是一个带工作线程的Service,新建一个IntentService就可以在其onHandleIntent()做耗时操作了,这个方法运行在工作线程中。
  • IntentSevice中的工作线程就是使用的HandlerThread,因为HandlerThread中有Looper,可以在主线程中(Service的onStart()方法)中向worker线程发送消息。
  • Looper是使用ThreadLocal存储的,Looper里面维护了一个消息队列。一个线程和一个Looper对应,Looper通过looper()方法取出MessageQueue中的Message,并把Message交给handler处理(message.target)
  • ThreadLocal 为每个线程中数据存取一份数据,各个线程之间互不影响。