美文网首页
Android Handler源码分析

Android Handler源码分析

作者: 没有了遇见 | 来源:发表于2022-07-11 17:05 被阅读0次

开头三连

  • Handler 是什么???

  • Handler 能做什么??

  • Handler 怎么做到的??

1.Handler 是什么
 A Handler allows you to send and process Message and Runnable objects associated with  a thread's MessageQueue. 
 Handler 允许开发者 发送,处理消息和处理一个运行中的子线程的消息队列  也就是handler能处理消息和处理其他线程的消息队列 
 Each Handler instance is associated with a single thread and that thread's messagequeue. 
 每个Handler 是和一个单独的线程以及线程的消息队列相关的
 When you create a new Handler it is bound to a Looper It will deliver messages and runnables to that Looper's messagequeue and execute them on that Looper's thread.
 创建一个新的Handler对象时  会和一个bound 绑定到一块   Handler 会把消息和消息队列在 looper的线程中执行


 Handler 能做什么??
 There are two main uses for a Handler:
 Handler 的两个重要作用
 to schedule messages and runnables to be executed at some point in the future;
 //1.处理消息 以及定时执行 
 and  to enqueuean action to be performed on a different thread than your own.
 //2.在不同的线程中执行任务

1.Handler 是什么

Handler是一个能发送与处理消息和线程中MessageQueue(消息队列)的对象
创建Handler的时候 会将消息队列和消息在Looper 的线程中执行

我理解的是 Hanler 是Android提供的处理跨线程和定时任务一种消息机制

Handler 是一种单线消息队列模式的一种消息机制,用于消息处理,定时任务,跨线程通讯.

单线消息队列模式:每个线程都有一个“流水线”,我们可往这条流水线上放“消息”,流水线的末端有工作人员会去处理这些消息

单线消息队列模式.png

2.能做什么

  • 处理消息
  • 延时执行任务
  • 将要在与您自己的线程不同的线程上执行的操作排入队列。

3.为什么要使用Handler?

Android中只有UI线程操作页面,但是UI线程又不能执行耗时操作,因此有耗时操作的时候需要放在子线程,下载完成和失败的时候我们需要进行跨线程操作,Handler就是提供跨线程操作的工具.

注意:
1:会不会创建多个Looper对象
一个线程只有一个Looper对象(根据线程创建的 所以一个线程只有一个对象)
Looper.myLooper() --->sThreadLocal.get();---> map.getEntry(this);)e.value;

3.怎么使用Handler

借的流程图.png

代码执行流程

关键类和关键函数

  • ActivityThread
    初始化UI线程的Looper和开启轮询
    main(String[] args)-->Looper.prepareMainLooper();和Looper.loop();
  • Looper
    初始化
    prepare()
    Looper存储到ThreadLocalMap
    sThreadLocal.set(new Looper(quitAllowed));
    looper初始化
    Looper(boolean quitAllowed)
    轮询
    loop()
    保证循环
    for (;;) {!loopOnce(me, ident, thresholdOverride) }
    轮询到消息
    Message msg = me.mQueue.next();
    //传递给handler 调用handler.dispatchMessage() msg.target==handler
    msg.target.dispatchMessage(msg);
  • Handler
    分发消息
    dispatchMessage(msg)
    执行回调
    mCallback.handleMessage(msg)
  • MessageQueue
    enqueueMessage() 加入队列
    next()取出消息

1.初始化Looper 初始化MessageQueue 开启循环获取消息

//初始化Looper 初始化MessageQueue  开启循环获取消息
1:ActivityThread  ---> main(String[] args) { Looper.prepareMainLooper();}-->
//初始化Looper
2:prepare(){ThreadLocal<Looper>    sThreadLocal.set(new Looper(quitAllowed)); }
//初始化Looper 创建消息队列 创建主线程
3:  private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
4:ActivityThread  ---> main(String[] args) { Looper.loop();}-->
// loopOnce() 调用 
  public static void loop() {
    ....
        for (;;) {
            if (!loopOnce(me, ident, thresholdOverride)) {
            //返回false 直接return
                return;
            }
        }
    }

  private static boolean loopOnce(final Looper me,
            final long ident, final int thresholdOverride){
      ...
//从消息队列取出消息
    Message msg = me.mQueue.next();
//消息为空直接返回false
 if (msg == null) {
            // No message indicates that the message queue is quitting.
            return false;
        }
      ...

1.第一步初始化Looper


初始化Looper.png
存储Looper对象.png
初始化Looper.png
  1. 开启循环轮询 Looper从MessageQueue 中轮询message


    开启轮询.png
    for死循环保证循环执行.png
    MessageQueue队列取出message.png
    取出数据.png
回到到Handler的dispatchMessage方法.png
回调给创建Handler的回调方法.png

3.handler 发送消息


发送消息.png
发送消息.png
添加消息队列.png
添加消息队列的方法.png

2.Handler 发送消息

handler.sendMessage()..  -->sendMessageAtTime()
// 发送消息  MessageQueue  消息队列将消息存储到消息队列
 public boolean sendMessageAtTime(@NonNull 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);
    }
  // 添加到消息队列 MessageQueue . enqueueMessage() 中设计唤醒和锁的操作有需要的可以深入操作
    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }


Message :Message的作用就是承载消息

Message obtain()和Message()  区别 

Message obtain() 会复用存在的消息对象  Message() 是直接创建对象
public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; 
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

MessageQueue 消息队列

每个线程都有且只有一个MessageQueue,他是一个用于承载消息的队列,内部使用链表作为数据结构,所以待处理的消息都会在这里排队

Message还涉及到一个关键概念:线程休眠。当MessageQueue中没有消息或者都在等待中,则会将线程休眠,让出cpu资源,提高cpu的利用效率。进入休眠后,如果需要继续执行代码则需要将线程唤醒。当方法暂时无法直接返回需要等待的时候,则可以将线程阻塞,即休眠,等待被唤醒继续执行逻辑。这部分内容也会在后面详细讲。

关键方法

  • 出队 -->next()
  • 进队 -->enqueueMessage()(中间设计到锁和休眠唤醒操作)

Looper 轮询器(UI 线程的Looper从ActivityThread的main方法开始)

关键方法

  • 初始化 -->prepare()
  • 开启循环 -->loop()(中间设计到锁和休眠唤醒操作)

ThreadLocal具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问到想要的值。当某些数据是以线程为作用域并且不同线程具有不同的数据副本的时候,就可以考虑采用ThreadLocal。

总结

Handler源码的简单梳理,整理了冲Ui线程创建looper 循环从MessageQueue获取消息 然后回传给Handler的源码路径,简单的整理出来Handler的调用路径
有一些深度的枷锁和休眠的一些代码未深入,有需要的可以再深入看看

码字不容易 ,欢迎点赞!!! 欢迎交流

相关文章

网友评论

      本文标题:Android Handler源码分析

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