一、什么是Handler
由于Android的只允许在UI线程(主线程)中修改UI组件,为了解决其他线程无法改变组件属性值而使用Handler类处理
作用:
- 在新启动的线程中发送消息
- 在主线程中获取处理消息
二、Handler的使用
1.post(Runnable)
post方法用于handleMessage()的作用一样处理数据更新UI,源码如下,也是调用sendMessageDelayed方法,省略了很多创建Handler的代码 (适用于处理单一情况)
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
2.sendMessage(Message)
sendMessage有多种发送消息的方式,有发送空数据和延迟两个属性,根据具体的情况选择和合适的方式
而且能发送不同类型消息,在handlMessage中处理。(适用于多种情况)
三、Handler内部机制
- Message:Hanler接收和处理的消息对象。
- MessageQueue:消息队列,使用FIFO(先进先出)的方式管理Message。创建Loop对象是,也会在构造器中创建MessageQuene对象
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
- Looper:每个线程只能拥有一个Looper,Looper的主要作用是负责读取MessageQueen的Message,读到的Message发送给Handler来处理。
- Handler:发送和处理消息,Handler正常工作必须在当前线程中拥有一个MessageQueen队列和管理MessageQueen的Looper
- 在UI线程中已经初始化一个Message和Looper,直接创建Handler即可以处理消息
- 新的线程中必须Looper.prepare();创建MessageQueen和Looper,然后 Looper.loop();方法启动
new Thread(new Runnable() {
@Override
public void run() {
try {
Looper.prepare();
sendHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO
}
};
Looper.loop();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
Looper.loop();的作用是通过死循环的方式不断地从MessageQueen中读取消息
四、Handler引起的内存泄漏以及解决方案
原因:在java中非静态内部类和匿名内部类都会隐式持有当前类的外部引用,由于Handler是非静态内部类所以其持有当前Activity的隐式引用,如果Handler没有被释放,其所持有的外部引用也就是Activity也不可能被释放,因此造成内存泄漏。比如Hander中延迟5min发送消息,在MessaageQueen中队列中持有Hander引用,这队列间接持有Activity引用
解决办法:
- 使用静态内部类,对Activity进行弱引用
private static class MyHandler extends Handler{
//持有弱引用HandlerActivity,GC回收时会被回收掉.
private final WeakReference<HandlerActivity> mActivty;
public MyHandler(HandlerActivity activity){
mActivty =new WeakReference<HandlerActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
HandlerActivity activity=mActivty.get();
super.handleMessage(msg);
if(activity!=null){
//执行业务逻辑
}
}
}
private static final Runnable myRunnable = new Runnable() {
@Override
public void run() {
//执行我们的业务逻辑
}
};
- 在onDestroy()中,四messageQueenqi清空
serHandler.removeCallbacksAndMessages(null);
五、如何使用Handler让子线程与子线程之间进行通信
1.创建两个子线程,分别在子线程内创建Hander对象
2.分别在子线程内发送消息
- 因为Looper.loop()是阻塞线程的因此在loop()之前发送消息
- 如果构造时不提供Looper类对象参数,会获取当前线程的Looper对象
网友评论