Handler中异步消息处理一般由四个部分组成,Message、Handler、MessageQueue和Looper。
1、Message :是在线程之间传递消息,它可以携带信息,用于不同线程之间交互数据。它里面字段有
waht、arg1、arg2(int类型)、object型数据。
2、Handler: 它主要用于发送消息和处理消息,发送消息一般是使用Handler的sendMessage()方法,
发出消息之后,辗转处理后,最终会传递到handlerMessage()中
3、MessageQueue:消息队列,它主要存放handler发送的消息。这部分消息会一直存放在队列中,等待
被处理。每个线程中只有一个MessageQueue队列。
4、Looper:是MessageQueue队列的管家,调用loop()方法后,就会进入到一个无线循环当中,然后每当
发现队列中有消息,就会取出,并传递到Handler的handlerMessage方法中()。
了解了上面的几个的基本概念之后,我们再把异步消息处理的流程梳理一遍,首先需要在主线程中创建一个Handler对象,并重写handlerMessage()方法。然后当子线程中更新UI的时候,我们先创建一个Message对象,并通过Handler发送出去。之后这条消息会被添加到MessageQueue队列中等待被处理,而Looper一直尝试从队列中取消息,最后分发到handlerMessage()方法中。由于Handler是在主线程创建的,所以handlerMessage()方法会在主线程中运行,于是我们就可以更新UI了。
以下是流程图:
总结:以上是Handler的运行机制,也是如何在子线程中辗转到主线程的流程!!
能不能在子线程中,创建Handler
new Thread() {
@Override
public void run() {
// 在子线程中发送异步消息
mHandler.sendEmptyMessage(101);
}
}.start();
标准写法:
// 初始化该线程Looper,MessageQueue,执行且只能执行一次
Looper.prepare();
// 初始化Handler对象,内部关联Looper对象
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
// 启动消息队列出栈死循环
Looper.loop();
要求我们必须创建一个Looper对象,所以在子线程创建Handler必须创建一个Looper。 只能创建一个Looper,创建两个也会报错。
总结:
- 一个线程只能存在一个Looper,只存在一个MessageQueue对象,可以存在N个Handler
- MessageQueue 是通过时间排序的
- android中两个子线程相互交互同样可以通过Handler的异步消息机制实现,可以在线程a中定义Handler对象,而在线程b中获取handler的引用并调用sendMessage方法
为什么主线程不会因为Looper.loop()里的死循环卡死
public static void main(String[] args) {
....
//创建Looper和MessageQueue对象,用于处理主线程的消息
Looper.prepareMainLooper();
//创建ActivityThread对象
ActivityThread thread = new ActivityThread();
//建立Binder通道 (创建新线程)
thread.attach(false);
Looper.loop(); //消息循环运行
throw new RuntimeException("Main thread loop unexpectedly exited");
}
1、:进入死循环前创建了新binder线程
2、.通过管道机制,主线程大多时候处于休眠状态,不会消耗大量cpu资源导致程序卡死
HandlerThread
正常用法:
/**
* 测试HandlerThread的基本使用
*/
HandlerThread mHandlerThread = new HandlerThread("myHandlerThreand");
mHandlerThread.start();
// 创建的Handler将会在mHandlerThread线程中执行
final Handler mHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
Log.i("tag", "接收到消息:" + msg.obj.toString());
}
};
Message msg = new Message();
msg.obj = "11111";
mHandler.sendMessage(msg);
}
HandlerThread继承Thread,本质就是一个线程,调用start()方法之后,后执行run方法:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
- 内部调用了Looper.prepate()方法和Loop.loop()方法,在android体系中一个线程其实是对应着一个Looper对象、一个MessageQueue对象,以及N个Handler对象。
- 所以通过run方法,我们可以知道在我们创建的HandlerThread线程中我们创建了该线程的Looper与MessageQueue;
不需要的时候需要手动释放:
protected void onDestroy() {
super.onDestroy();
mHandlerThread.quit();
}
总结:
- HandlerThread本质上是一个Thread对象,只不过其内部帮我们创建了该线程的Looper和MessageQueue;
- 通过HandlerThread我们不但可以实现UI线程与子线程的通信同样也可以实现子线程与子线程之间的通信;
- HandlerThread在不需要使用的时候需要手动的回收掉;