handler机制:其实就是Android消息传递机制。概括起来就是通过handler的sendMessage或者postDelayed方法将消息发送到messageQueue中,然后通过lLooper.loop()方法从中取出message进行处理。下面具体说说 从handler的使用说起:初始化阶段
private static class TestHandler extends Handler {
private final WeakReference<TestFragment> fragmentWeakReference;
private TestHandler(TestFragment fragment) {
fragmentWeakReference = new WeakReference<>(fragment);
}
@Override
public void handleMessage(Message msg) {
AnchorPerspectiveLiveRoomFragment fragment = fragmentWeakReference.get();
super.handleMessage(msg);
}
}
}
mHandler = new TestHandler(this);
这里是在fragment中,所以采用弱引用fragment的方式定义(防内存泄漏),创建handler时候一般是Looper.prepare();new Handler();Looper.loop();这里之所以没有写prepare和loop,是因为我这里是在主线程中创建的handler,而且要往主线程的looper中发送消息,主线程的这两个方法在ActivityThread类中的main函数中已经调用了。接下来是发送消息,之所以是采用obtainMessage的方式创建消息,主要是为了利用系统自动的创建和回收这个message,发送则直接send。
Message msg = mHandler.obtainMessage();
msg.obj = "test";
mHandler.sendMessage(msg);
上面基本的使用,接下来我们看看到底干了什么,首先从Looper.prepare()开始
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));
}
在这个方法中创建了一个looper,并把它保存在了threadLocal中。这里的threadLocal其实就是一个类,这个类保存了looper的相关信息。紧接着是looper的具体创建
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
就是创建了一个messageQueue并获取当前线程。然后是Handler创建,这里的new Handler,虽然没有传递参数,但是它重写了handleMessage方法,这个放到后面讲(如果采用handler.post(runnable)的话其实是创建了一个有callback的handler(它的回调就是runnable),那么它源码如下
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
就是prepare中创建的那个looper,而mQueue也是刚才创建looper时新建的messageQueue,callback则是传进来的。 重点就这么几行,为looper赋值:它的具体实现则是
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
接着就是发送消息,他最终会调用Handler.java中下面的方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
这里的enqueueMessage其实就是向消息队里里插入一条message,具体实现则是修改链表的指针。由于已经调用了looper.loop方法,所以我们看看这里做了什么
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
}
}
重点就这么几行,在这个for循环中不断的取消息,然后通过dispatchMessage(handler中的)方法将消息发送到相应回调中。之所以是handler中的方法,是因为Message中的变量

public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
可以看出,如果没有callback,也就是那个runnable,那么就调用重写的handleMessage方法。到这里基本上是完事了。但是细心的可能会发现,在loop方法中有个死循环(for(;;)),他不会造成ANR吗,答案是不会的。原因在于
-
ANR的定义:当前事件没有得到机会处理(有可能是因为主线程正常处理其他的事件,而不能及时处理当前的事件)。 当前事件正在处理了,但是没有及时处理完成。
-
Android中所有事件都是通过loop来传递的,比如生命周期的回调。所以在for循环中取出消息来执行,如果卡顿了,可能会造成ANR,从而阻塞了loop的循环,而不是loop的循环阻塞了事件的处理。换句话说,通过定义可以看出,要想产生ANR首先得拿到处理的消息,无限循环中拿不到消息,肯定也就不会产生ANR
可以用如下的图来大致的表示一下流程

ThreadLocal:线程本地变量,ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。它里面比较重要的方法就是set,get,比如下面的ThreadLocal.set
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
就是向map中插入数据
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
这里需要说明的ThreadLocalMap,其实他是一个定制化的hashmap,只是用来存储线程的本地变量值,key是ThreadLocal,值为Object,这里为looper。
HandlerThread:它是继承自Thread的类,本质上是一个线程,只不过它内部封装了一个handler,并且在run方法中主动调用了prepare和loop方法
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
所以使用场景就是:如果需要在子线程中使用handler就直接用。也就是子线程与主线程通信。避免多线程并发导致空指针问题,利用它获取looper对象,下面是一个简单的小例子
/**
* 子线程与主线程进行信息交互步骤
* 1.创建主线程handler
* 2.创建handlerThread获取looper对象
* 3.利用looper创建子线程handler
* 4.在主线程中利用子线程的handler向子线程发送消息
* 5.在子线程中利用主线程的handler向主线程发送消息
*/
public class Main2Activity extends AppCompatActivity implements View.OnClickListener {
private Button mBtn1,mBtn2;
//主线程handler
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
Message message = new Message();
System.out.println("main Handler");
//给子线程发送消息
threadHandler.sendMessageDelayed(message,1000);
}
};
//子线程handler
private Handler threadHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
HandlerThread thread = new HandlerThread("handlerThread");
thread.start();
threadHandler = new Handler(thread.getLooper()){
@Override
public void handleMessage(Message msg) {
Message message = new Message();
System.out.println("thread Handler");
//给主线程发送消息
handler.sendMessageDelayed(message,1000);
}
};
mBtn1 = (Button) findViewById(R.id.button2);
mBtn2 = (Button) findViewById(R.id.button3);
mBtn1.setOnClickListener(this);
mBtn2.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button1:
handler.sendEmptyMessage(1);
break;
case R.id.button2:
handler.removeMessages(1);
break;
default:
break;
}
}
}