Handler是Android中的异步消息处理机制。当发送一个消息之后,这个消息是进入一个消息队列(MessageQueue),在消息队列中通过Looper去循环的获取队列中的消息,然后将消息分派给对应的处理者进行处理。
线程一旦被创建就会生成一个Looper对象,有且仅有一个。每个应用在运行的时候都会创建一个主线程(mainThread)。
主线程不能做耗时操作,子线程不能更新UI。
UIThread通常就是mian thread,而Android启动程序的时候就会替它建立一个MessageQueue。
Message:存储需要处理操作的信息
MessageQueue:先进先出,存储handler发送过来的消息
Looper:循环器,它是消息队列和handler的通信媒介,
1:循环的取出消息队列中的消息;
2:将取出的消息发送给对应的处理者
Handler:主线程和子线程的通信媒介,
1:添加消息到消息队列;
2:处理循环器分派过来的消息
因为Android的UI控件不是线程安全的,如果在多线程并发访问UI控件可能会导致不可预期的状态。
锁机制会使访问UI逻辑复杂,并且降低UI的访问效率,锁会阻塞某些线程的执行。
同进程线程间内存共享,通过handler通信,消息的内容是不需要从一个线程拷贝到另一个线程,因为两个线程间可使用的内存是同一个区域。(注意:线程私有区域ThreadLocal)
管道的作用就是当一个线程准备好Message,并放入消息池,这时需要通知了一个线程B去处理这个消息。线程A向管道的写端写入数据,管道有数据便会唤醒线程B去处理消息。管道的作用是用于通知另一个线程的,这便是最核心的作用。
从内存角度,通信过程中binder涉及到一次内存拷贝,handler机制中的Message根本不需要拷贝,本身就是在同一片内存。
从CPU角度,为了Binder通信底层驱动还需要创建一个binder线程池,每次通信涉及binder线程的创建和内存的分配等比较浪费CPU资源
原因:handler发送的消息在当前handler的消息队列中,如果此时activity被finish掉了,那么消息队列的消息依旧由handler进行处理,若此时handler申明为内存类(非静态内部类),内部类持有外部类的实例引用,这样在GC垃圾回收时发现Activity还有其他引用存在,因而就不会去回首这个Activity,进而导致Activity泄漏。
方法:使用静态内部类,并且使用WeakReference包裹外部类的对象。首先静态内部类不持有外部类的引用,使用静态的handler不会导致activity的泄漏,handler定义static的同时,还要用WeakReference包裹外部类的对象。
MyHandler handler = new MyHandler(this);public static class MyHandler extends Handler {private WeakReference reference;public MyHandler(MainActivity activity) {reference = new WeakReference(activity);}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case 1:Log.i("test",textView.getText().toString());break;default:break;}}
}@Override
protected void onDestroy() {super.onDestroy();//避免activity销毁时,messageQueue中的消息未处理完;故此时应把对应的message给清除出队列handler.removeCallbacks(postRunnable); //清除runnable对应的message
}
使用 Handler 机制,首先需要创建一个Handler 对象,可以直接使用Handler 无参构造函创建Handler 对象,或者是继承Handler类,重写 handleMessage(Message msg)方法来创建handler对象。Google 官方提供了一个推荐的使用方式,代码如下∶
Class LooperThread extends Thread {public Handler mHandler;public void run(){Looper.prepare();mHandler = new Handler(){public void handleMessage(Message msg){// process incoming messages here}};Looper.loop();}
}
通过上一部分的分析,读者应该能够很容易理解上面这种方式。但是在实际的开发实践中,大部分的Handler 对象都是在主线程中创建的,此时已经存在了Looper 对象,并不需要调用Loopr.prepare()与 Looper.loop()方法,直接构建一个Handler 对象即可∶
//调用new Thread(new MyThread()).start();// handle private final Handler handler = new Handler(){ public void handleMessage(Message msg){ switch (msg.what) { case 1://更新UI}} super.handleMessage(msg); } }; // threadprivate class MyThread implements Runnable{@Override public void run(){ while(true){ try{ Thread.sleep(60*1000);//延时操作Message message = new Message(); message.what = 1; handler.sendMessage(message); }catch (Exception e) { } } } }
获取 Message 大概有如下几种方式。推荐使用前两种方式进行创建,原因是不需要重复去新建Message,可以节省内存空间。
Message message = myHandler.obtainMessage(); //通过 Handler 实例获取
Message message1 = Message.obtain(); //通过 Message 获取
Message message2 = new Message(); //直接创建新的 Message 实例