Android Framework学习七:Handler、Looper、Message

news2025/5/23 4:33:48

文章目录

  • 简介
  • Looper
  • Message
  • MessageQueue
  • Handler
  • Framework学习系列文章

简介

在这里插入图片描述
Looper当做一台传送装置,MessageQueue是传送带,传送带上放的是Message,Handler用于发送Message分发与接收处理。

Looper

frameworks/base/core/java/android/app/ActivityThread.java
ActivityThread.main是APP的入口函数,先调用Looper.prepareMainLooper创建Looper,再调用Looper.loop让它跑起来。

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        Looper.loop();
    }

frameworks/base/core/java/android/os/Looper.java

public final class Looper {
...
    // sThreadLocal.get() will return null unless you've called prepare().
    @UnsupportedAppUsage
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    @UnsupportedAppUsage
    private static Looper sMainLooper;  // guarded by Looper.class
    private static Observer sObserver;

    @UnsupportedAppUsage
    final MessageQueue mQueue;
    final Thread mThread;
    ...
}

ThreadLocal 是 Android 和 Java 中一个用于实现线程隔离的工具类,它能让每个使用该变量的线程都拥有独立的副本,线程间对该变量的操作互不影响。
在这里插入图片描述
APP入口函数会调用prepareMainLooper->prepare, 会新建一个Looper对象给
sThreadLocal,保证线程有且拥有一个只有自己能用的Looper对象。
sMainLooper通过myLooper函数赋值,其实就是sThreadLocal中的Looper对象

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

Looper.loop
loop()其实是在一个死循环中,不断执行loopOnce函数

    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    @SuppressWarnings("AndroidFrameworkBinderIdentity")
    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        if (me.mInLoop) {
            Slog.w(TAG, "Loop again would have the queued messages be executed"
                    + " before this one completed.");
        }

        me.mInLoop = true;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("persist.log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        me.mSlowDeliveryDetected = false;

        for (;;) {
            if (!loopOnce(me, ident, thresholdOverride)) {
                return;
            }
        }
    }

在loopOnce中会调用msg.target.dispatchMessage(msg)分发消息

    private static boolean loopOnce(final Looper me,
            final long ident, final int thresholdOverride) {
            ....
        Message msg = me.mQueue.next(); // might block
        ....
        try {
            msg.target.dispatchMessage(msg);
            if (observer != null) {
                observer.messageDispatched(token, msg);
            }
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } catch (Exception exception) {
            if (observer != null) {
                observer.dispatchingThrewException(token, msg, exception);
            }
            throw exception;
        } finally {
            ThreadLocalWorkSource.restore(origWorkSource);
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        ....    
    }

这个msg.target的target其实是Handler对象,msg.target.dispatchMessage调用的是Handler.dispatchMessage

Message

这个target就是Handler, 也就是Message中会有Handler的引用,
frameworks/base/core/java/android/os/Message.java

    /**
     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, and <em>obj</em>
     * members.
     * @param h  The <em>target</em> value to set.
     * @param what  The <em>what</em> value to set.
     * @param obj  The <em>object</em> method to set.
     * @return  A Message object from the global pool.
     */
    public static Message obtain(Handler h, int what, Object obj) {
        Message m = obtain();
        m.target = h;
        m.what = what;
        m.obj = obj;

        return m;
    }

MessageQueue

MessageQueue是由链表组成的,用于存放Message
在这里插入图片描述
MessageQueue主要函数
在这里插入图片描述

Handler

发送Message时sendMessage最终都会调用enqueueMessage

    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

    /**
     * Enqueue a message into the message queue after all pending messages
     * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
     * Time spent in deep sleep will add an additional delay to execution.
     * You will receive it in {@link #handleMessage}, in the thread attached
     * to this handler.
     *
     * @param uptimeMillis The absolute time at which the message should be
     *         delivered, using the
     *         {@link android.os.SystemClock#uptimeMillis} time-base.
     *
     * @return Returns true if the message was successfully placed in to the
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    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);
    }

会调用queue.enqueueMessage,这个queue其实是MessageQueue,把Message放入MessageQueue

    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);
    }

接收到消息后处理时
dispatchMessage会调用到handleMessage,就会进入Message的处理部分
frameworks/base/core/java/android/os/Handler.java

    /**
     * Callback interface you can use when instantiating a Handler to avoid
     * having to implement your own subclass of Handler.
     */
    public interface Callback {
        /**
         * @param msg A {@link android.os.Message Message} object
         * @return True if no further handling is desired
         */
        boolean handleMessage(@NonNull Message msg);
    }

    /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(@NonNull Message msg) {
    }

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

Framework学习系列文章

Android Framework学习一:系统框架、启动过程
Android Framework学习二:Activity创建及View绘制流程
Android Framework学习三:zygote
Android Framework学习四:APP速度优化
Android Framework学习五:APP启动过程原理及速度优化
Android Framework学习六:Binder原理
Android Framework学习七:Handler、Looper、Message
作者:帅得不敢出门

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2383611.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MyBatis:简化数据库操作的持久层框架

1、什么是Mybatis? MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由 apachesoftwarefoundation 迁移到了google code,由谷歌托管,并且改名为MyBatis 。 2013年11月迁移到Github。 iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框…

【001】RenPy打包安卓apk 流程源码级别分析

1. 入口在下图 2. SDK版本及代码入口 &#xff08;renpy-8.3.7-sdk&#xff09; 由于SDK一直在升级&#xff0c;本文采用 标题中的版本进行分析&#xff0c;整体逻辑变化不太大。 实际执行逻辑是调用的rapt 2.1 点击按钮实际执行逻辑 def AndroidIfState(state, needed, acti…

物理信息神经网络(PINNs)在悬臂梁分析中的应用研究

一、引言 物理信息神经网络(Physics-Informed Neural Networks, PINNs)是近年来兴起的一种结合深度学习与传统物理建模的创新方法。本文将探讨PINNs在悬臂梁力学分析中的应用&#xff0c;展示如何利用这一技术解决工程力学中的经典问题。 二、PINNs基本原理 PINNs的核心思想是…

论文浅尝 | HOLMES:面向大语言模型多跳问答的超关系知识图谱方法(ACL2024)

笔记整理&#xff1a;李晓彤&#xff0c;浙江大学硕士&#xff0c;研究方向为大语言模型 论文链接&#xff1a;https://arxiv.org/pdf/2406.06027 发表会议&#xff1a;ACL 2024 1. 动机 多跳问答&#xff08;Multi-Hop Question Answering, MHQA&#xff09;技术近年来在自然语…

jenkins使用Send build artifacts over SSH发布jar包目录配置

本测试用ruoyi-plus的代码。 1 [GitLab 自动触发 Jenkins 构建_jenkins构建触发器没有build when a change is pushed to git-CSDN博客](https://blog.csdn.net/wangyiyungw/article/details/81776972) 2 [jenkins使用Send build artifacts over SSH遇到的坑-CSDN博客](https…

uni-app小程序登录后…

前情 最近新接了一个全新项目&#xff0c;是类似商城的小程序项目&#xff0c;我负责从0开始搭建小程序&#xff0c;我选用的技术栈是uni-app技术栈&#xff0c;其中就有一个用户登录功能&#xff0c;小程序部分页面是需要登录才可以查看的&#xff0c;对于未登录的用户需要引…

【深度学习基础】从感知机到多层神经网络:模型原理、结构与计算过程全解析

【深度学习基础】从感知机到多层神经网络&#xff1a;模型原理、结构与计算过程全解析 1. 引言 神经网络的重要性&#xff1a; 作为人工智能的核心技术之一&#xff0c;神经网络通过模拟人脑神经元的工作机制&#xff0c;成为解决复杂模式识别、预测和决策任务的利器。从图像分…

解决Power BI Desktop导入Excel数据第一行不是列标题问题

选中第一行不是列标题的表→鼠标右键→选择编辑查询→进入Power Query界面→点击“将第一行用作标题”→点击左边的“关闭并应用” 第一行就提升为标题了

springboot3.x只需两步快速整合nacos作配置中心

一、下载依赖 我在网上找了各种资料&#xff0c;都是要先确定springcloud版本&#xff0c;实际操作却可能由于版本或者镜像或者maven等问题报红&#xff0c;出现各种情况。 实际只需要指定特定版本号就行&#xff0c;添加下面两个依赖 <dependency><groupId>com.…

<uniapp><vuex><状态管理>在uniapp中,如何使用vuex实现数据共享与传递?

前言 本专栏是基于uniapp实现手机端各种小功能的程序&#xff0c;并且基于各种通讯协议如http、websocekt等&#xff0c;实现手机端作为客户端&#xff08;或者是手持机、PDA等&#xff09;&#xff0c;与服务端进行数据通讯的实例开发。 发文平台 CSDN 环境配置 系统&…

数据湖和数据仓库的区别

在当今数据驱动的时代&#xff0c;企业需要处理和存储海量数据。数据湖与数据仓库作为两种主要的数据存储解决方案&#xff0c;各自有其独特的优势与适用场景。本文将客观详细地介绍数据湖与数据仓库的基本概念、核心区别、应用场景以及未来发展趋势&#xff0c;帮助读者更好地…

【论文阅读 | AAAI 2025 | FD2-Net:用于红外 - 可见光目标检测的频率驱动特征分解网络】

论文阅读 | AAAI 2025 | FD2-Net&#xff1a;用于红外 - 可见光目标检测的频率驱动特征分解网络 1.摘要&&引言2. 方法2.1总体架构2.2特征分解编码器2.3多模态重建机制2.4训练损失 3.实验3.1实验设置3.2主要结果3.3消融研究 4.结论 题目&#xff1a;FD2-Net: Frequency-…

济南国网数字化培训班学习笔记-第三组-1-电力通信传输网认知

电力通信传输网认知 电力通信基本情况 传输介质 传输介质类型&#xff08;导引与非导引&#xff09; 导引传输介质&#xff0c;如电缆、光纤&#xff1b; 非导引传输介质&#xff0c;如无线电波&#xff1b; 传输介质的选择影响信号传输质量 信号传输模式&#xff08;单工…

OAT 初始化时出错?问题可能出在 PAM 配置上|OceanBase 故障排查实践

本文作者&#xff1a;爱可生数据库工程师&#xff0c;任仲禹&#xff0c;擅长故障分析和性能优化。 背景 某客户在使用 OAT 初始化OceanBase 服务器的过程中&#xff0c;进行到 precheck 步骤时&#xff0c;遇到了如下报错信息&#xff1a; ERROR - check current session ha…

1-机器学习的基本概念

文章目录 一、机器学习的步骤Step1 - Function with unknownStep2 - Define Loss from Training DataStep3 - Optimization 二、机器学习的改进Q1 - 线性模型有一些缺点Q2 - 重新诠释机器学习的三步Q3 - 机器学习的扩展Q4 - 过拟合问题&#xff08;Overfitting&#xff09; 一、…

Hass-Panel - 开源智能家居控制面板

文章目录 ▎项目介绍&#xff1a;预览图▎主要特性安装部署Docker方式 正式版Home Assistant Addon方式详细安装方式1. Home Assistant 插件安装&#xff08;推荐&#xff09;2. Docker 安装命令功能说明 &#xff1a;3. Docker Compose 安装升级说明Docker Compose 版本升级 功…

Ubuntu搭建NFS服务器的方法

0 工具 Ubuntu 18.041 Ubuntu搭建NFS服务器的方法 在Ubuntu下搭建NFS&#xff08;网络文件系统&#xff09;服务器可以让我们像访问本地文件一样访问Ubuntu上的文件&#xff0c;例如可以把开发板的根文件系统放到NFS服务器目录下方便调试。 1.1 安装nfs-kernel-server&#…

网感驱动下开源AI大模型AI智能名片S2B2C商城小程序源码的实践路径研究

摘要&#xff1a;在数字化浪潮中&#xff0c;网感已成为内容创作者与商业运营者必备的核心能力。本文以开源AI大模型、AI智能名片及S2B2C商城小程序源码为技术载体&#xff0c;通过解析网感培养与用户需求洞察的内在关联&#xff0c;提出"数据驱动-场景适配-价值重构"…

COMPUTEX 2025 | 广和通5G AI MiFi解决方案助力移动宽带终端迈向AI新未来

随着5G与AI不断融合&#xff0c;稳定高速、智能的移动网络已成为商务、旅行、户外作业等场景的刚需。广和通5G AI MiFi方案凭借领先技术与创新设计&#xff0c;重新定义5G移动网络体验。 广和通5G AI MiFi 方案搭载高通 4nm制程QCM4490平台&#xff0c;融合手机级超低功耗技术…

防范Java应用中的恶意文件上传:确保服务器的安全性

防范Java应用中的恶意文件上传&#xff1a;确保服务器的安全性 在当今数字化时代&#xff0c;Java 应用无处不在&#xff0c;而文件上传功能作为许多应用的核心组件&#xff0c;却潜藏着巨大的安全隐患。恶意文件上传可能导致服务器被入侵、数据泄露甚至服务瘫痪&#xff0c;因…