什么是handler
handler是一套 Android 消息传递机制,这里的消息指的是message类,可以理解成handler是对message进行传递的一种机制。
handler的作用
在多线程的应用场景中,将工作线程中需更新UI的操作信息 传递到 UI主线程,从而实现 工作线程对UI的更新处理,最终实现异步消息的处理
相关概念
主线程:
又可以称作UI线程,当应用程序启动时,会自动开启主线程
子线程:
又可以称为工作线程,开发自己创建的线程,可以用来执行耗时操作
Message:
可用于线程间通信,时线程间通讯的一种数据单元,存储了需要操作的通信信息
Message Quenue
消息队列,一种先进先出的数据结果,存储着Handler发送的消息
handler
message的处理者,发送和接收message
添加Message到Message Quene,处理Looper分派过来的Message
Looper:
循环器,循环去除消息队列(Message Quenue)的消息(message);将取出的Message发送给对应的Handler
注意点:
每个线程中只能拥有1个looper ,1个Looper可以绑定多个线程的Handler。
handler使用
方式1:使用 Handler.sendMessage()
步骤1:
在主线程中创建handler
class mHandler extends Handler {
// 通过复写handlerMessage() 从而确定更新UI的操作
@Override
public void handleMessage(Message msg) {
...// 需执行的UI操作
}
}
private Handler mhandler = new mHandler();
步骤2:创建Message
Message msg = Message.obtain();//实例化消息对象,obtain采用的为对象池,防止多次创建对象
msg.what = 1; // 消息标识
msg.obj = "AA"; // 消息内容存放
步骤3:
在子线程中通过Handler发送消息到消息队列中
mHandler.sendMessage(msg);
步骤4:开启工作线程
方式2:使用Handler.post()
// 步骤1:在主线程中创建Handler实例
private Handler mhandler = new mHandler();
// 步骤2:在工作线程中 发送消息到消息队列中 & 指定操作UI内容
mHandler.post(new Runnable() {
@Override
public void run() {
... // 需执行的UI操作
}
});
// 步骤3:开启工作线程(同时启动了Handler)
// 多线程可采用AsyncTask、继承Thread类、实现Runnable
handler 工作原理
注意点:
1个线程(Thread)只能绑定 1个循环器(Looper),但可以有多个处理者(Handler)
1个循环器(Looper) 可绑定多个处理者(Handler)
1个处理者(Handler) 只能绑定1个1个循环器(Looper)
handler部分源码分析
暂时学识浅薄,后续补上
handler内存泄漏
垃圾回收机制:
Java虚拟机中使用可达性分析的算法来决定对象是否可以被回收。即通过GCRoot对象为起始点,向下搜索走过的路径(引用链),如果发现某个对象或者对象组为不可达状态,则将其进行回收。
产生内存泄漏的整体原因
内存泄漏指的就是有些对象(短周期对象)没有用了,但是却被其他有用的类(长周期对象)所引用,从而导致无用对象占据了内存空间,形成内存泄漏。
handler产生内存泄漏的复现
handler做一个延时操作,没等message被处理,activity进行销毁操作。
发现强制GC也不能回到初始值,说明产生了内存泄漏
handler内存泄漏的原因
1.内部类默认持有了外部类的引用,所以handler持有它的外部activity类
2.根据持有路径分析:
主线程 —> threadlocal —> Looper —> MessageQueue —> Message —> Handler —> Activity
这种情况下程序还存活的时候,主线程不会销毁,自然不会GC activity对象,导致内存泄漏
注意:这种情况是message还没处理完,activity就销毁了
解决方法
1.说到底,就是activity被销毁,已经是没用了,但是还是被Handler持有,导致不能被释放,导致内存泄漏
所以一种想法就是让handler不持有activity
// 设置为:静态内部类
private static class FHandler extends Handler{
// 定义 弱引用实例
private WeakReference<Activity> reference;
// 在构造方法中传入需持有的Activity实例
public FHandler(Activity activity) {
// 如果想使用Activity实例,则用WeakReference弱引用持有Activity实例
reference = new WeakReference<Activity>(activity); }
@Override
public void handleMessage(Message msg) {
}
}
2.当外部类结束生命周期时,清空Handler内消息队列
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
// 外部类Activity生命周期结束时,同时清空消息队列 & 结束Handler生命周期
}
HandlerThread 实现 子线程和主线程直接双向通信,具体用法
使用步骤:
//1、创建HandlerThread对象,即创建了一个新的线程,参数为线程名,仅仅是标记线程用的
HandlerThread mHandlerThread = new HandlerThread("mHandlerThread");
//2、开启线程,第一步创建了一个新的线程,此处开启线程。
mHandlerThread.start();
//3、创建Handler,并重写handleMessage()方法
//new Handler(mHandlerThread.getLooper()),即把该Handler绑定到mHandlerThread线程的Looper,
//进而绑定到了线程mHandlerThread
Handler mHandlerInHandlerThread = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
//对信息的相关处理操作
//在子线程mHandlerThread中运行
super.handleMessage(msg);
}
};
//4、创建消息并发送消息
//在主线程中
Message msg = Message.obtain();
//主线程向子线程mHandlerThread发送消息通信
mHandlerInHandlerThread.sendMessage(msg);
//5、结束线程。之前开启线程,当工作结束不再使用该线程时,应该结束该线程
//即停止了线程的消息循环
mHandlerThread.quit();