对Handler的一些理解(速记篇)

一、什么是handler?

handler是Android给我们提供用来更新UI的一套机制,也是消息处理机制。

二、为什么要使用Handler

一个Android应用程序被创建时就会创建一个进程,该进程用应用的包名作为进程名。该进程会启动主线程ActivityThread,也叫做UI主线程,但有时需要做些耗时操作,为了不能够去阻塞UI主线程的正常运行,我们将它放在子线程中进行操作,操作完成后需要绘制UI,但Android子线程不能直接操作UI线程的,所以通过Handler来进行通信 

三、为什么Android子线程不能直接操作主线程?

Android UI线程不是线程安全的,如果多线程并发的话就会造成界面混乱,不可控的状态。那为什么不能让主程序加上锁机制,这样就能够线程安全了?可上锁就会有造成访问的逻辑变得很麻烦、很复杂,并且会阻塞其他线程的执行,导致性能下降。综上问题,Android采用单线程模型来处理UI操作。 

Handler中五个重要的类

  • Handler:负责发送和处理消息。
  • Message:用来携带需要的数据。
  • MessageQueue:消息队列,内部存储结构是采用单链表的数据结构来存储消息列表的,其中主要有插入enqueue()和从中拿走并删除next()两个方法。
  • Looper:消息轮巡器/消息泵/消息循环,不停的从MessageQueue中取Message。以无限循环的方式去查找是否有新消息,如有就去处理,若没有就standby(等待)。
  • ThreadLocal: 让当前线程与looper绑定 并确保只有一个

Handler的消息处理机制

一、Handler

由于Handler主要负责发送和处理消息,那我们主要实现它的sendMessage、handlerMessage、dispatchMessage三个方法,来处理消息的发送和接收:

sendMessage:把当前Handler和Message绑定 然后发送到MessageQueue

当然源码里是这样写的 :

    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }


    public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }

 
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }

 
    public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }

 可以看到 无论是send什么Message 最后是返回sendMessageAtTime

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

 sendMessageAtTime返回的是enqueueMessage方法

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

 enqueueMessage方法中的 msg.target = this 就是把当前handler和Message绑定在一起

然后返回的又是MessageQueue里面的enqueueMessage方法  这个方法会把Message储存进MessageQueue中

/**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }
    
    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
  • 我们在Handler的构造函数中获取当前线程对应的looper,并取出Looper中对应的消息队列保存在成员变量中。
  • sendMessage方法中我们给Message的target变量赋值为this,也就是表明了Message是由当前的Handler来负责处理的,
  • 之后调用enqueueMessage方法将消息存入消息队列中。
  • 而dispatchMessage方法我们实现比较简单,负责调用handleMessage来处理消息。

二、Looper

Looper主要负责取出消息交由Handler处理,我们主要来实现prepare、loop方法:

Looper.myLooper() 

从当前线程中的ThreadLocal中取出Looper实例。如果Looper为null的话就会抛异常,抛出的异常内容翻译过来就是

无法在未调用Looper.prepare()的线程内创建handler

所以 在调用Looper.myLooper()之前必须要先调用Looper.prepare()方法

Looper.prepare();

prepare() 方法中则是实例化了一个Looper,然后将Looper放进进ThreadLocal中

在我们调用Looper.prepare方法时也将MessageQueue实例化了

ThreadLocal 

ThreadLocal.set方法是把当前looper存入Threadlocal中与当前线程绑定

在调用Looper.myLooper方法之前必须必须已经调用了Looper.prepare方法,即在实例化Handler之前就要调用Looper.prepare方法

主线程中Android系统已经帮我们调用了Looper.prepare方法

Looper.loop() :从MessageQueue中取出消息然后发给Handler处理

该方法中有个死循环  

循环里面 MessageQueue的next方法取出消息

然后调用消息的   .target.dispatchmessage方法 

target是与Message绑定的handler

dispatchmessage是handler的方法里面调用了HandlerMessage方法处理消息


三、Message

message里面有个target值 是用来绑定handler方法的


四、MessageQueue

这里的next和enqueueMessage是典型的生产者、消费者的关系,为防止出现错乱我们给两个方法都加上Lock锁,当enqueueMessage方法存放消息时如果当前队列消息满了,则调用mFullQueue.await();进行等待消息处理,当向消息队列中存放消息后,也就是说消息队列不为空了,调用mEmptyQueue.signalAll();通知next()方法来处理消息。


1、Handler的工作原理

  在使用Handler之前必须要调用Looper.prepare()这句代码,这句代码的作用是将Looper与当前的线程进行绑定,在实例化Handler的时候,通过Looper.myLooper()获取Looper,然后再获得Looper中的MessageQueue。在子线程中调用Handler的sendMessage方法就是将Message放入MessageQueue中,然后调用Looper.loop()方法来从MessageQueue中取出Message,在取到Message的时候,执行 msg.target.dispatchMessage(msg);这句代码,这句代码就是从当前的Message中取出Handler然后执行Handler的handleMessage方法

2、Handler、Message、MessageQueue以及Looper之间的关系

它们的关系如下图(图片来源于网上)


Android在子线程更新UI的最常见的五种方式 (这里不讲解AsyncTask(异步任务))

     1、runOnUiThread()方法

     2、handler.post()方法


 

     3、handler.sendMessage()方法


     4、view.post()方法。

     5、view postDelayed(Runnable,long)

         前四种是慕课网老师讲解的,最后一种是疯狂Android讲义书籍上有的一种

猜你喜欢

转载自blog.csdn.net/qq_42259105/article/details/82983242