请选择 进入手机版 | 继续访问电脑版

Android消息传递机制Handler完全解析之4内存泄漏等问题

[复制链接]
阿峻 发表于 2021-1-1 18:29:38 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
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,如果调用多次创建的方法会抛出异常。
部分源码代码如下:
  1.         //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()方法开启消息轮询的,否则会报错。
部分源码如下:
  1.     /**     * 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销毁后还在收发消息,造成内存泄漏。

  1. /**      * 声明一个静态的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){                                }          }      }
复制代码
共勉:往前走


来源:https://blog.csdn.net/wenzhi20102321/article/details/111940136
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

发布主题

专注素材教程免费分享
全国免费热线电话

18768367769

周一至周日9:00-23:00

反馈建议

27428564@qq.com 在线QQ咨询

扫描二维码关注我们

Powered by Discuz! X3.4© 2001-2013 Comsenz Inc.( 蜀ICP备2021001884号-1 )