Android消息传递机制Handler完全解析之4内存泄漏等问题
Android消息传递机制Handler完全解析之内存泄漏等问题
Android Handler的使用还是要注意几个地方的,比如方法的调用和界面退出了Handler消息还在导致内存泄漏等情况。
top
1、在子线程使用Handler前一定要先为子线程创建Looper,并且让子线程工作
Looper创建的方式是直接调用Looper.prepare()方法,让子线程工作的方法是Looper.loop().
过创建Handler对象时如果没有给它指定Looper,那么它默认会使用当前线程的Looper,而线程默认是没有Looper的,所以使用前一定要先创建Looper。
如果在主线程创建子线程工作的Handler,需要給Handler传入子线程对象HandlerThead。
2、在同一个线程里,Looper.prepare()方法不能被调用两次。因为同一个线程里,最多只能有一个Looper对象。
一个线程里面只能有一个Loooper和一个MessageQueue,如果调用多次创建的方法会抛出异常。
部分源码代码如下:
//Looper对外暴露的创建Looper方法 public static void prepare() { prepare(true); }//参数表示是否允许强制退出,一般是允许的 private static void prepare(boolean quitAllowed) {//sThreadLocal.get()返回的是跟Looper绑定的对象,如果该对象已经创建,不能再调用prepare方法,否则会抛出异常。 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); }//第一次调用prepare,就会创建Looper,并且把Looper跟ThreadLocal绑定 sThreadLocal.set(new Looper(quitAllowed)); }//这里是私有方法,只能自身调用//MessageQueue就是这里实例化的//一些耗时处理都是在Thread中实现的 private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed);//创建MessageQueue mThread = Thread.currentThread(); }
3、只有调用了Looper.loop()方法,Handler机制才能正常工作。
Looper负责管理MessageQueue,它的loop()方法负责从MessageQueue里取出消息并交给Handler处理,
所以如果没有调用Looper.loop()方法,消息就不会被取出和处理。
主线程Looper.loop()方法是Activity创建的时候调用了的,不要我们管,子线程是要我们自己调用的。
调用两次loop方法会怎么样?
源码里面没有报异常,但是loop方法里面有取消息的循环,但是如果多次调用,里面会有多个取消息的循环,是同一个MessageQueu里面取消息,所以多个循环也是没用的,最后还是按顺序一个一个取。
4、Looper.loop()方法一定要在调用了Looper.prepare()方法之后调用。
那是因为如果当前线程还没有Looper,是不能调用Looper.loop()方法开启消息轮询的,否则会报错。
部分源码如下:
/** * Looper的核心方法 */ public static void loop() { final Looper me = myLooper();//要先调用Looper.prepare(),否则会报错,因为Looper没有实例化 if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue;...}
5、不要在主线程调用Looper.prepare()方法。
这是因为在Android系统创建主线程的时候就已经调用了Looper.prepare()方法和Looper.loop()方法,
这也是为什么我们在主线程使用Handler时不需要调用这两个方法的原因。
6、当我们在子线程使用Handler时,如果Handler不再需要发送和处理消息,那么一定要退出子线程的消息轮询。
如果页面退出,也记得把Handler的消息清空,比如在Activity 退出的回调方法onDestroy中对消息进行清除。
Handler.removeCallbacksAndMessages(null);
7、使用Message.obtain()来获取Message消息对象。
避免过多创建对象。
8、如果在Activity界面接收消息,一般使用弱引用,避免消息在Activity销毁后还在收发消息,造成内存泄漏。
/** * 声明一个静态的Handler内部类,并持有外部类的弱引用 */ private static class MyHandler extends Handler{ private final WeakReference mActivty; private MyHandler(HandlerActivity mActivty) { this.mActivty = new WeakReference(mActivty); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); HandlerActivity activity = mActivty.get();// 判断Activity没被销毁才继续.... if (activity != null){ } } }
共勉:往前走
更多相关文章
- Android结合kotlin使用coroutine的方法实例
- 详解Android(安卓)消息处理机制
- 控制UI界面的方法
- Android消息机制底层原理
- Flutter事件分发源码剖析
- Android消息传递之基于RxJava实现一个EventBus - RxBus
- Android(安卓)Service使用方法--简单音乐播放实例
- 盛大开源软件一览表
- Android(安卓)Handler的使用(二)