无冥冥之志者,无昭昭之明;无惛惛之事者,无赫赫之功。
 解释:没有专心致志地刻苦学习,就没有融会贯通的智慧;没有埋头执着的工作,就不会取得显著的成就。

Handler消息机制

   Handler消息机制是Android中普遍使用的一种机制。在Android开发中,不管是系统开发还是应用开发都必须了解的一种机制。

1. 用来干什么?

   Handler消息机制是用来进行 线程之间 通信的。Android有一个重要的特点,那就是需要在主线程才能进行UI界面的更新,而对于一些特殊的场景,比如在子线程中获取到数据需要更新到UI界面,就必须进行线程间的通信,通过把数据交给主线程,由主线程进行UI更新。

   在Android开发过程中,为了不影响UI界面的操作流程性,常常会创建工作线程去完成耗时操作,然后将耗时操作的结果返回给主线程,因此线程之间的通信是很重要的。

2.怎么用?使用过程中有什么注意点?

   Handler的使用非常简单,步骤如下:

  • 在Activity创建Handler对象:创建对象的时候需要重写handleMessage方法。
    Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            //处理消息
        }
    };
  • 发送消息
    new Thread(new Runnable() {
        @Override
        public void run() {
            Message msg = new Message();
            handler.sendMessage(msg);
        }
    }).start();

   上述三个步骤就是Handler的简单使用。Handler的创建在主线程中进行,重写的handleMessage方法中的参数就是需要处理的消息。需要处理的消息是在子线程中发出的,最终在主线程中(handleMessage方法)得到处理,这就完成了线程间通信。

   Activity中可以如此简单的使用Handler得益于系统在主线程给我们初始化了Handler消息机制的一些工作。

注意点

   上边Handler的使用仍存在需要注意的地方,那就是 内存泄露 问题,这个问题留到后文去解决。

3.实现原理?原理学习过程中,有什么收获?

   通过源码的阅读学习,Handler的实现原理涉及到的类:

  • Handler:Handler负责往这个消息队列存放消息,或者处理Looper取出来的消息
  • Looper:负责监控消息队列中是否有消息需要处理。
  • MessageQueue:消息队列,存放等待处理的消息。
  • Message:作为消息的承载主体,当需要使用Handler消息机制的时候,首先需要使用Message记录需要传递消息的内容。
Handler消息机制的流程

   Handler消息机制的实现流程是:首先,调用Looper的 *prepare 方法;它是一个静态方法,在这个方法中,会创建一个Looper对象,并把这个对象存放在ThreadLocal中,这样做的目的是确保一个线程只能有一个Looper对象。在Looper的构造函数中,会创建一个MessageQueue对象。这样MessageQueue和Looper都准备好了。接着是创建Handler对象,并且重写 handleMessage 方法,这个方法用于接收待处理的消息对象。最后,调用Looper的 loop 方法,这个方法开启一个死循环,不断的从Message Queue中获取消息。如果MessageQueue没有消息需要处理,线程进行休眠;如果有消息需要处理,那么消息将被取出来,交给Handler的handleMessage*进行处理。Handler消息机制流程就是这样运行的。源代码太多了,不打算这文章中贴源代码

   在阅读源码的过程中,我对Handler消息机制流产生了一些问题:

  • 为什么在子线程用handler的sendMessage发送类消息,就能传递到主线程类呢?
  • Looper的loop方法是一个死循环,那么它不是一直运行着的吗?休眠是一个什么状态?
  • loop方法既然休眠了,那么当有消息需要处理的时候,它又是怎么样被唤醒的呢?

   第一个问题:子线程发送消息的时候,使用的是主线程中创建的Handler,那么使用主线程的Handler发送消息,最终消息回到走的是主线程的Handle消息机制。那么为什么子线程可以使用主线程创建的Handler?这是因为线程资源共享。

   其他两个问题需要深入底层才能找到答案。

注意点:

一、常见的创建Message的方式:
  • Message msg = new Message();
  • Message msg = message.obtain();
  • Message msg = handler.ontainMessage();

   以new的方法直接创建message就像新创建一个对象一样,需要重新申请内存。而以message.obtainhandler.ontainMessage的方式创建Message,得到的Message对象是重对象池中得到的,这种方式可以避免过多创建对象。

二、内存泄露

   Handler的内存泄露问题的原因在于使用下面语句创建Handler的时候,内部类持有外部类的引用。

    Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            //处理消息
        }
    };

   当Activity需要,由于Handler对象持有Activity的引用,导致Activity和Handler对象都不能被回收,引发了内存泄露。那么正确的做法是:把Handler定义成静态内部类,最好在Handler类内部使用弱引用持有Activity 的引用。

    static  class MyHandler extends Handler{ 
        WeakReference<Activity> weakReference;
        public MyHandler(Activity a){
            weakReference = new WeakReference<>(a);
        }
        @Override
        public void handleMessage(@NonNull Message msg) {
          super.handleMessage(msg);
          Activity a = weakReference.get();
        }
    }

   Handler的消息机制暂时写到这,还有一些问题没有解决,知识点也还不够全面,这些内容在后续会相继补上。

results matching ""

    No results matching ""