Android--HandlerThread使用及源码解析

1、HandlerThread基本使用

在之前的《Android--掌握Handler、Looper、MessageQueue的基友关系》,我们写过一个实现Main线程给子线程发送消息的方法,没有看过的可以去上面的文章再看一下。下面我们使用另一种方式即:通过HandlerThread来实现Main线程给子线程发送消息:

private HandlerThread mHandlerThread;
private Handler mThreadHandler;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_handler_intent);
    initHandler();
    mThreadHandler.sendEmptyMessage(0);
    L.D("发送消息及所在线程:" + Thread.currentThread());
}

private void initHandler() {
    mHandlerThread = new HandlerThread("thc_test");
    mHandlerThread.start();
    mThreadHandler = new Handler(mHandlerThread.getLooper()){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            L.D("收到消息及所在线程" + Thread.currentThread());
        }
    };
}

打印的日志如下:
发送消息及所在线程:Thread[main,5,main]
收到消息及所在线程Thread[thc_test,5,main]说明发送成功了。

//停止从MessageQueue中取出消息
public void stop(){   
   mHandlerThread.quit();
}

结论
可以看到,这里我们不用再自己进行初始化一个Looper,而是直接使用了HandlerThread中初始化的Looper(即:通过HandlerThread.getLooper()方法获得Looper),其实在HandlerThread中初始化Looper也是和我们自己初始化的方式一样,只不过多了一些判断处理等。

2、HandlerThread源码及应用场景使用
mHandlerThread = new HandlerThread("thc_test");
mHandlerThread.start();

HandlerThread的使用就像我们使用普通的线程,new一个Thread,然后调用它的start方法启动线程。去看HandlerThread的源码,它继承Thread,就要重写它的run()方法,但是它的run()方法有些不同:

@Override
public void run() {
    mTid = Process.myTid();
    //先new一个Looper  set到 ThreadLocal对应线程的副本中
    Looper.prepare();
    synchronized (this) {
        //从ThreadLocal中取出该Looper
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    //轮询当前线程MessageQueue中的消息
    Looper.loop();
    mTid = -1;
}

从上面注释也可以看出,在run()方法中,先得到一个Looper.prepare()得到一个Looper,然后进入一个同步方法(后面再说为什么要对这个方法进行同步处理),然后开始Looper.loop进行不断的轮询从MessageQueue中取出消息。

接下来,初始化在Handler:

mThreadHandler = new Handler(mHandlerThread.getLooper()){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            L.D("收到消息及所在线程" + Thread.currentThread());
        }
    };

先看一下mHandlerThread.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;
}

mLooper是HandlerThread的成员变量,在run()方法中的同步方法中赋值。这里的getLooper其实就是获取这个mLooper。
总结:
一个Thread对应一个Looper和一个MssageQueue,而这个Looper在哪个线程初始化,那么这个Looper和MessagQueue就属于该线程,同时由该Looper作为构造参数初始化的Handler处理的也是该线程的消息。所以,如果我们想实现主线程控制子线程去操作的时候就使用HandlerThread可以了。

为什么使用同步方法呢:Looper和Handler两个实例的初始化分别是在两个线程中,为了解决这两个线程的同步问题。当mLooper == null的时候就wait,等待run方法中给mLooper赋值,赋值成功之后Handler才会创建成功,然后发送、处理的消息都是该线程的Looper取出和压入栈中的消息。

你可能感兴趣的:(Android--HandlerThread使用及源码解析)