IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> android源码--Handler原理 -> 正文阅读

[移动开发]android源码--Handler原理

handler基本原理基本都理解,但是有些细节时间一久仍会有所遗忘,做些整理也还是有必要的。

一、handler原理整体概述

首先,Handler相关的原理机制形象的描述为以下情景:

Handler:快递员
Message:包裹
MessageQueue:快递分拣中心(分拣传送带)
Looper:快递公司(处理包裹去向)

handler原理图

MessageQueue 是一 个消息队列 , 它是采用单链表的数据结构来存储消息的,因为单链表在插入删除上 的效率非常高。

Looper持有MessageQueue。在循环开启后,不断的从MessageQueue中取出MessageQueue进行处理。

Handler机制可以简述为:
Handler将Message发送到Looper的消息队列中,即MessageQueue,等待Looper的循环读取Message,处理Message,然后调用Message的target,即附属的Handler的dispatchMessage()方法,将该消息回调到handleMessage()方法中,然后完成更新UI操作。

Handler发送消息Handler.post最终也是调用的sendMessageAtTime()。所以MessageQueue中的Message是按设定的消息处理时间,按照时间先后顺序排列的。

二、源码解析

Handler在创建的时候就会获取当前线程的Looper来构造消息循环系统,获取的方式就是通过ThreadLocal。
在Android的系统机制中,以下机制中都使用到了ThreadLocal:Looper、ActivityThread、ActivityManagerService。

1、新建Handler源码分析

Handler、Looper、MessageQueue关系:
Handler中持有Looper和MessageQueue。Handler创建的时候需要传入一个Looper,或者从ThreadLocal中取当前的Looper。
Looper中持有MessageQueue,在创建Looper的时候,MessageQueue对象也被创建好了,MessageQueue的数据结构其实并不是队列,而是采用了单链表的形式,因为单链表在插入和删除时,比队列有优势。

Handler中必须持有一个Looper。这个Looper如果没有传入,则会从ThreadLocal中取。

Handler.java

public class Handler {
    final Looper mLooper;
    final MessageQueue mQueue;    
···
    public Handler() {
        this(null, false);
    }
}
    public Handler(@Nullable Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

2、ThreadLocal分析

Handler内部通过ThreadLocal获取到当前线程的Looper

看下myLooper方法
Looper.java

public final class Looper {
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
final MessageQueue mQueue;
···
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
}

sThreadLocal是静态的。从源码中可以看出Looper是持有MessageQueue的。ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,最终通过ThreadLocalMap存储。

ThreadLocal并不是线程,它的作用是可以在每个线程中存储数据。ThreadLocal可以在不同的线程之中互不干扰地存储并提供数据,通过ThreadLocal可以轻松获取每个线程的Looper。当然需要注意的是,线程是默认没有Looper的,如果需要使用Handler就必须为线程创建Looper。

ThreadLocal是一种多线程间并发访问变量的解决方案。与其synchronized等加锁的方式不同,ThreadLocal完全不提供锁,为每个线程提供变量的独立副本,以保障线程安全,其实现原理就是每个thread都有一个ThreadLocalMap。使用ThreadLocal可以在一定程度上减少锁竞争。

ThreadLocal.java

public class ThreadLocal<T> {
···
    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();
    }
    //ThreadLocalMap是从当前线程中获取的
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

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

}

从源码中可知ThreadLocalMap存在于每个thread中。

ThreadLocalMap.java

    static class ThreadLocalMap {
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

        /**
         * The initial capacity -- MUST be a power of two.
         */
        private static final int INITIAL_CAPACITY = 16;

        /**
         * The table, resized as necessary.
         * table.length MUST always be a power of two.
         */
        private Entry[] table;

ThreadLocalMap里面有一个table,里面通过Entry保存了键值对数据。

从ThreadLocal的set和get方法可以看出,它们所操作的对象都是当前线程的localValues(ThreadLocalMap)对象的table数组,因此在不同线程中访问同一个ThreadLocal的set和get方法,它们对ThreadLocal所做的读写操作仅限于各自线程的内部,这就是为什么ThreadLocal可以在多个线程中互不干扰地存储和修改数据。

3、子线程中创建Handler

Android中新开启的线程,是没有开启消息循环的,如果要在线程中使用Handler,那么就要先调用Looper.prepare。android中在子线程使用Handler,可以参考HandlerThread。

主线程中在ActivityThread类中通过调Looper.prepareMainLooper(),自动创建了Looper对象。

Looper.java

public final class Looper {
    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的prepare源码如上所示,当从sThreadLocal没获取到Looper时,preprare方法会先new一个Looper,并保存到ThreadLocal中。

参考:
https://blog.csdn.net/singwhatiwanna/article/details/48350919
https://blog.csdn.net/qq_16188829/article/details/76922757
https://blog.csdn.net/yu540135101/article/details/82668686

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-26 12:12:28  更:2021-07-26 12:13:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/24 14:55:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码