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){                                }          }      }

共勉:往前走

更多相关文章

  1. Android结合kotlin使用coroutine的方法实例
  2. 详解Android(安卓)消息处理机制
  3. 控制UI界面的方法
  4. Android消息机制底层原理
  5. Flutter事件分发源码剖析
  6. Android消息传递之基于RxJava实现一个EventBus - RxBus
  7. Android(安卓)Service使用方法--简单音乐播放实例
  8. 盛大开源软件一览表
  9. Android(安卓)Handler的使用(二)

随机推荐

  1. Android基础学习【历史流程重走】 ---- A
  2. achartengine(Google给android提供的绘图
  3. Android添加自定义系统服务
  4. Android开发Tips(3)
  5. android loginDemo +WebService用户登录
  6. android 实现指定wifi切换
  7. Android 开发艺术探索笔记(五) 之 Android
  8. android解锁屏幕实例
  9. Android - 设置adb的usb连接配置
  10. Android 多媒体应用——SoundPool音频播