美文网首页
浅析Handler机制原理

浅析Handler机制原理

作者: Tank_Mao | 来源:发表于2021-11-04 11:33 被阅读0次

Android的UI线程主要负责处理用户的按键事件、用户触屏事件以及屏幕绘图事件等,耗时操作放在后台进程进行。
那么,UI线程与后台线程之间必然需要进行通信,于是就引入了Handler机制,也就是Android线程间的消息传递机制。
在阅读了Android Handler机制相关的源代码后,做了如下笔记:

一、Handler机制中的主要角色

Handler流程图.png

1.Handler

A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. 
Each Handler instance is associated with a single thread and that thread's message queue.
 When you create a new Handler it is bound to a Looper. 
It will deliver messages and runnables to that Looper's message queue and execute them on that Looper's thread.

There are two main uses for a Handler: 
(1) to schedule messages and runnables to be executed at some point in the future; 
and (2) to enqueue an action to be performed on a different thread than your own.

以上是官方的解释,大概意思如下:
Handler对象和单个线程和这个线程的消息队列相关联,当你创建Handler的时候,他就绑定了一个Looper。(个人理解:就是说Handler,Looper,Thread,MessageQueue这些东西是耦合在一块的)

Handler主要有两个作用:
1.安排messages和runnables在将来某个时间点被执行
2.将一个操作加入队列,在别的线程执行。

官方说的太抽象,可以参考Handler流程图中步骤2和4。

2.Looper

Class used to run a message loop for a thread.
 Threads by default do not have a message loop associated with them;
 to create one, call prepare in the thread that is to run the loop, and then loop to have it process messages until the loop is stopped.
Most interaction with a message loop is through the Handler class.

Looper用来为一个线程进行消息循环,默认的线程是没有关联Looper的,你得调用prepare方法,然后再调用loop方法让它处理messages,直到循环被中止。

参考Handler流程图中步骤3。

3.MessageQueue

Low-level class holding the list of messages to be dispatched by a Looper. 
Messages are not added directly to a MessageQueue, but rather through Handler objects associated with the Looper.
You can retrieve the MessageQueue for the current thread with Looper.myQueue().

包含由Looper调度的消息列表的低级类。Messages不是直接被添加到MessageQueue的,而是通过关联了Looper的Handler对象来做这个事情。你可以用Looper.myQueue()来获取到当前线程的MessageQueue。

简而言之,MessageQueue就是一个消息队列,先进先出,用来管理message。

4.Message

Defines a message containing a description and arbitrary data object that can be sent to a Handler. 
This object contains two extra int fields and an extra object field that allow you to not do allocations in many cases.
While the constructor of Message is public, 
the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() methods,
 which will pull them from a pool of recycled objects.

Message包含两个额外的int字段和一个你在许多情况下不用做分配的Object字段。
获取Message最好的方法是调用Message.obtain()或者Handler.obtainMessage(),这两个方法将会从回收利用的池子里给你捞出一个message给你用,减少了内存开销。

二、Handler使用实例

获取百度首页的数据,并展示到TextView中

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    TextView tv;
    Handler mHandler;
    private static final int MSG_TO_MAIN = 111;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv = findViewById(R.id.tv);

        //创建Handler对象
        mHandler = new Handler(Looper.getMainLooper()){
            @Override
            public void handleMessage(Message message){
                super.handleMessage(message);
                switch (message.what){
                    case MSG_TO_MAIN:
                        tv.setText((String)message.obj);
                        break;
                    default:
                        break;
                }
            }
        };

    }

    /**
     *
     * @param view R.id.button
     */
    public void requestData(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    //使用okHttp进行网络请求
                    OkHttpClient  client = new OkHttpClient();
                    Request request = new Request.Builder()
                            .url("https://www.baidu.com")
                            .build();
                    Response response = client.newCall(request).execute();
                    String result = response.body().string();
                    //将result反馈给主线程
//                    Message message = Message.obtain();
                    Message message = mHandler.obtainMessage();
                    message.what = MSG_TO_MAIN;
                    message.obj = result;
                    mHandler.sendMessage(message);
//                    message.sendToTarget();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

这是一个后台线程向主线程发送消息的例子,值得注意的是,在这个例子里我们没有调用Looper.prepare()和Loop.loop(),这是因为主线程的looper是由Android环境创建的,我们不用自己调用。

三、Handler机制源码分析

以上内容,我们只是搞清楚了Handler机制的大概流程,但是具体实现又是怎么样的呢,下面我们带着问题追踪一下每一个步骤的源码:

Question1: Loop.prepare()是在干什么?

/**
 *Initialize the current thread as a looper. 
 *This gives you a chance to create handlers that then reference this looper, before actually starting the 
 *loop. 
 *Be sure to call loop() after calling this method, and end it by calling quit().
 */
public static void prepare() {
        prepare(true);
 }

private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
 }

看到这里,它的大概意思是要将looper绑定到当前线程,也就是说一个线程有且只有一个looper。而且looper是线程隔离的,你有你的looper,我有我的looper,互不干涉。

然而,这只是我们的一个直观感受,它的真实面目是这样的吗,我们还能接着研究这一行代码:

   sThreadLocal.set(new Looper(quitAllowed));

要弄清楚这一行代码,就得搞清楚ThreadLocal,ThreadLocalMap和Thread之间的关系。


三者关系.png

ThreadLocal是一个泛型类,她负责维护内部的ThradLocalMap,ThreadLocalMap用于存储线程隔离的变量,比如Looper。

ThreadLocal结构.png

下面主要看一下ThradLocal的get和set方法:

//set
public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
}

//get
public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
}

至此,我们对Looper.prepare()有了一个大概的了解,但是关于ThreadLocal还有很多问题值得探讨,本文旨在浅析Hanler机制的原理,所以跳过关于ThreadLocal的一些疑问,接着往下看。

Question2: Loooper.loop()发生了什么?

//关键代码
public static void loop() {
    final Looper me = myLooper();
    ...
    //死循环,一直处理
    for(; ;){
        if(!loopOnce(me, ident, thresholdOverride)){
            return;
        }
    }
}

接下来,我们就不得不看看loopOnce这个方法了

//仅展示关键代码
private static booloean loopOnce(final Looper me, final log ident , final int thresholdOverride){
    ...
    msg.target.dispatchMessage(msg);
    ...
}

相关文章

  • 浅析Handler机制原理

    Android的UI线程主要负责处理用户的按键事件、用户触屏事件以及屏幕绘图事件等,耗时操作放在后台进程进行。那么...

  • Android Handler机制9--HandlerThrea

    移步Android Handler机制详解 1 工作原理 内部原理 = Thread类 + Handler类机制...

  • Android Handler机制原理浅析

    源码分析 1 Handler从创建对象到发送消息sendMessage()的过程做了什么 步骤: 步骤1 创建ha...

  • Handler(一)--流程图

    系列目录: Handler机制原理

  • 消息机制

    消息机制Handler的工作原理 Android中的消息机制主要就是指Handler的运行机制,而Handler的...

  • Android中Handler机制原理浅析

    对于我们来说Handler机制是日常开发中经常用到的,我们可以使用它轻松实现线程间的切换和延时操作。今天我们就来分...

  • 三分钟看懂Handler原理

    Handler机制的工作原理 Handler 工作流程基本包括 Handler、Looper、Message、Me...

  • Handler

    一,什么是handler 二,handler的使用 三,handler机制原理 四,handler引起的内存泄漏和...

  • Handler机制浅析

    本文我们主要是要介绍Handler机制,但是涉及到Handler又不得不介绍Message,MessageQueu...

  • Handler机制浅析

    前言 Android应用程序是基础Java语言,内部封装了消息队列,然后在主线程开启了死循环不断获取消息并处理来实...

网友评论

      本文标题:浅析Handler机制原理

      本文链接:https://www.haomeiwen.com/subject/ehgqzltx.html