安卓异步通信:Handler源码分析

Android Handler机制(线程间通信)↑ 在Android中,提供了异步消息处理机制的两种方式来解决线程之间的通信问题,一种是Handler机制,还有一种是AsyncTask机制。 1.handler 我们都知道,Android UI是线程不安全的,如果在子线程中尝试进行UI操作,程序就会崩溃。相信大家在日常的工作当中都会经常遇到这个问题,解决的方案应该也是早已烂熟于心,即创建一个Message对象,然后借助Handler发送出去,之后在Handler的handleMessage()方法中获得刚才发送的Message对象,然后在这里进行UI操作就不 阅读详情

核心类方法浅析

Handler:
sendMessage/post:将消息发送到消息队列中
dispatchMessage:将消息分发给对应Handler
handleMessage:依据消息进行相关处理/操作

MessageQueue:
enqueueMessage:将消息依据时间放入消息队列(入队)
next:从消息队列取出消息(出队)

Looper:
prepare:创建一个循环器+消息队列实例
loop:消息循环(即从消息队列取出消息并发给Handler)

源码分析

依旧采用由使用步骤深入分析

Handler.sendMessage()

①创建Handler对象:

实际调用:

public Handler() {
   this(null, false);
}
public Handler(Callback callback, boolean async) {
          mLooper = Looper.myLooper();
          if (mLooper == null) {
              throw new RuntimeException(
                  "Can't create handler inside thread that has not called Looper.prepare()");
          }

          mQueue = mLooper.mQueue;
}

创建Handler对象的过程也就是将Handler绑定至循环器+消息队列的过程:通过myLooper获取当前线程的循环器对象并赋值绑定、由循环器获得消息队列进行赋值绑定。
此处发现用来绑定的循环器和消息队列并没有在构造方法中创建,那么这两个实例是何时生成的?

注:①之前的隐式操作:循环器+消息队列实例生成、消息循环开始
上述描述中循环器通过Looper.prepare进行生成,而该方法在安卓应用启动时即被调用生成:

publicstatic void main(String[] args) {
    ...

    Looper.prepareMainLooper(); 
    ActivityThread thread = new ActivityThread(); 
    // 创建主线程
    Looper.loop(); 
    // 自动开启 消息循环

}

通过主线程调用prepareMainLooper创建应用的主线程循环器

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

    sThreadLocal.set(new Looper(true));
}

prepare方法首先进行是否重复调用判断(ThreadLocal是否已存在)
然后再生成该线程的循环器并设置进去

private Looper(boolean quitAllowed) {

    mQueue = new MessageQueue(quitAllowed);

    mRun = true;
    mThread = Thread.currentThread();
}

循环器构造方法中会生成对应的消息队列,并将当前线程与其绑定起来
上述分析了主线程循环器的创建+子线程由手动创建循环器发生的一系列操作

在循环器+消息队列创建成功后,消息的循环loop()随即开始:

public static void loop() {
        ...

        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        
        final MessageQueue queue = me.mQueue;
        
        for (;;) {
        Message msg = queue.next(); 
        if (msg == null) {
            return;
        }

        msg.target.dispatchMessage(msg);

        msg.recycle();
        }
}

消息循环开启:首先通过相关循环器获取消息队列,遍历消息将每个消息发送至其对应Handler,发送完成后回收资源

消息遍历过程next():

  Message next() {
	    ...

	    // 该参数用于确定消息队列中是否还有消息
	    // 从而决定消息队列应处于出队消息状态 or 等待状态
	    int nextPollTimeoutMillis = 0;

	    for (;;) {
	        if (nextPollTimeoutMillis != 0) {
	            Binder.flushPendingCommands();
	        }

	    // nativePollOnce方法在native层,若是nextPollTimeoutMillis为-1,此时消息队列处于等待状态 
	    nativePollOnce(ptr, nextPollTimeoutMillis);

	    synchronized (this) {
	 
	        final long now = SystemClock.uptimeMillis();
	        Message prevMsg = null;
	        Message msg = mMessages;

	        // 出队消息,即 从消息队列中取出消息:按创建Message对象的时间顺序
	        if (msg != null) {
	            if (now < msg.when) {
	                nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
	            } else {
	                // 取出了消息
	                mBlocked = false;
	                if (prevMsg != null) {
	                    prevMsg.next = msg.next;
	                } else {
	                    mMessages = msg.next;
	                }
	                msg.next = null;
	                if (DEBUG) Log.v(TAG, "Returning message: " + msg);
	                msg.markInUse();
	                return msg;
	            }
	        } else {

	            // 若 消息队列中已无消息,则将nextPollTimeoutMillis参数设为-1
	            // 下次循环时,消息队列则处于等待状态
	            nextPollTimeoutMillis = -1;
	        }

	        ......
	    }
	       .....
	   }
}

loop会进行消息循环取出操作(无限for循环),包含:①通过nextPollTimeoutMillis控制下一个消息出队时间及循环等待状态 ②有消息时进行消息出队相关操作

消息分发过程dispatchMessage(msg):

  public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }

            handleMessage(msg);
        }
    }

通过msg内容是否包含callBack判断执行哪种通信方式(sendMessage/post):sendMessage:调用handleMessage;post:调用handleCallBack(即调用传入的run())

所以第一步整体执行的操作:
隐式:①主线程自动生成循环器+消息队列(子线程手动生成)
②开启消息循环(loop()),循环将消息出队并分发给对应Handler
显示:创建Handler实例(与对应循环器+消息队列绑定)

②创建消息对象
Message msg = Message.obtain(); // 实例化消息对象
msg.what = 1; // 消息标识
msg.obj = "AA"; // 消息内容存放

源码分析:

public static Message obtain() {

      synchronized (sPoolSync) {
          if (sPool != null) {
              Message m = sPool;
              sPool = m.next;
              m.next = null;
              m.flags = 0; // clear in-use flag
              sPoolSize--;
              return m;
          }
      }
      return new Message();
  }

obtain实际是从消息池中取出可用消息对象进行复用(若池子用完则创建新实例使用)

③发送信息sendMessage
public final boolean sendMessage(Message msg)
  {
      return sendMessageDelayed(msg, 0);
  }

发送信息实际调用sendMessageDelayed,逐层向下分析

public final boolean sendMessageDelayed(Message msg, long delayMillis)
 {
     if (delayMillis < 0) {
         delayMillis = 0;
     }

     return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
 }
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;

        return enqueueMessage(queue, msg, uptimeMillis);
    }

上述获取消息队列,用于准备将消息放入队列

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
     msg.target = this;       

    return queue.enqueueMessage(msg, uptimeMillis);
}

该步将对应Handler记录到msg中,以便分发时调用,然后再消息入队

boolean enqueueMessage(Message msg, long when) {
   ...

   synchronized (this) {
       msg.markInUse();
       msg.when = when;
       Message p = mMessages;
       boolean needWake;

       // 判断消息队列里有无消息
           // a. 若无,则将当前插入的消息 作为队头 & 若此时消息队列处于等待状态,则唤醒
           if (p == null || when == 0 || when < p.when) {
               msg.next = p;
               mMessages = msg;
               needWake = mBlocked;
           } else {
               needWake = mBlocked && p.target == null && msg.isAsynchronous();
               Message prev;

           // b. 判断消息队列里有消息,则根据 消息(Message)创建的时间 插入到队列中
               for (;;) {
                   prev = p;
                   p = p.next;
                   if (p == null || when < p.when) {
                       break;
                   }
                   if (needWake && p.isAsynchronous()) {
                       needWake = false;
                   }
               }

               msg.next = p; 
               prev.next = msg;
           }

           if (needWake) {
               nativeWake(mPtr);
           }
       }
       return true;
}

放入队列操作:判断当前队列是否有消息(相当于判断循环状态)①有消息:依据时间节点插入合适位置 ②没有消息:当前消息作为头部放入,并判断是否需要唤醒

上述一系列信息发送操作实质:
将消息与其目标Handler绑定起来,再依据消息时间放入消息队列等待循环出队

至此,sendMessage流程即分析完毕,上述黑体字就是整个流程的关键操作

Handler.post()

①主线程创建handler实例

此步骤同上述sendMessage方法,进行隐式处理、绑定等动作

②工作线程发送信息
mHandler.post(new Runnable() {
       @Override
       public void run() {
           ... // 需执行的UI操作 
       }

});

post方法的处理,逐层深入:

public final boolean post(Runnable r)
   {
      return  sendMessageDelayed(getPostMessage(r), 0);
   }
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    
    m.callback = r;
    return m;
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
 {
     if (delayMillis < 0) {
         delayMillis = 0;
     }

     return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
 }

从sendMessageDelayed开始就与sendMessage()相同了
上述操作就是将post传入的runnable实例封装成一个message,再进行消息发送等任务,剩余就和发送消息处理完全相同。

循环中消息处理:

public static void loop() {
      ...
      final Looper me = myLooper();
      if (me == null) {
          throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
      }
      
      final MessageQueue queue = me.mQueue;
      for (;;) {
      
      Message msg = queue.next(); 
      if (msg == null) {
          return;
      }
      msg.target.dispatchMessage(msg);
      msg.recycle();
      }
}
public void dispatchMessage(Message msg) {
      if (msg.callback != null) {
          handleCallback(msg);
      } else {
          if (mCallback != null) {
              if (mCallback.handleMessage(msg)) {
                  return;
              }
          }
          handleMessage(msg);
      }
  }

在dispatchMessage中,因为之前封装消息时,将run赋值给了callBack,所以此处处理情况与sendMessage不同,触发handleCallback

private static void handleCallback(Message message) {
    message.callback.run();
}

该方法就直接调用先前runnable实例中实现的run方法

至此post实现过程分析完毕,与sendMessage实际只多了封装消息步骤与run方法调用

android与服务器实现http异步通信 本程序示例了android与服务器交互的代码,并带有android端和服务器端,帮助用户快速入门。 立即下载

相关推荐

多思计算机组成原理实验:模型机课程设计

计算机组成原理实验教程 基于多思网络虚拟实验系统 张雯雰

Nick的博客 2万+

Android中线程间的异步通信机制

循序渐进,介绍Android中线程间的异步通信机制。包括了Handler的使用及实现原理、HandlerThread的使用及实现原理、IntentService的使用及实现原理。AsyncTask的使用及实现原理。

麒麟操作系统安装达梦数据库ARM版

Linux安装达梦数据库ARM版

运维@小兵的博客 8767

Android 线程间通信机制 —— Handler消息通信

Android Handler Looper Message MessageQueue

Yang_Mao_Shan的博客 1460

学Simulink--决策规划场景实例:基于Simulink的智能车辆行为决策仿真

本文基于Simulink平台构建智能车辆变道决策仿真系统,采用MOBIL算法实现"决策-规划-执行"全流程。系统包含自车动力学模型、环境感知模块(含5%噪声)、决策控制器和轨迹规划模块,通过五次多项式实现平滑变道。仿真验证了三种典型工况:正常变道(成功率100%)、邻车拒绝让行和紧急避障,各项指标均满足要求(TTC>3s,横向加速度<2m/s²,决策周期<100ms)。文章详细介绍了建模步骤、核心算法实现和参数配置方法,并提出了强化学习、多车协同等优化方向。该模型为智能

amy_mhd的博客 151

SAP 供应商寄售(VMI)完整实现方案

摘要:本文详细讲解了SAP系统中供应商寄售(Consignment)和VMI(供应商管理库存)的实现方法。核心逻辑是物料所有权属于供应商,仅在领用时才触发采购。文章包含配置步骤(物料主数据、供应商设置、定价协议、会计科目等)、端到端操作流程(收货、库存查询、领用、结算、付款)、关键差异比较(与普通采购的区别)、核心事务码和数据表。重点说明了寄售流程无需采购订单,通过信息记录维护价格,领用时才产生应付账款的特点,并提供了常见问题解决方案和VMI进阶优化建议。

金牌架构师 1044

Android 线程间通信 - Handler 使用篇

Handler,可谓是面试题中的一个霸主了。几乎没有哪家公司,在面试的时候是不问这个问题的。简单一点,问问使用流程,内存泄漏等问题。

m0_70749039的博客 488

【2024年5月备考新增】《2024高项论文精华版(5)项目工作绩效域和度量绩效域》

3、专注于工作过程和能力。③专注于工作过程和能力。1、制定有效的度量指标。2、度量内容及相应指标。3、展示度量信息和结果。4、管理沟通和参与。7、监督新工作和变更。①制定有效的度量指标。②度量内容及相应指标。③展示度量信息和结果。5、基于度量进行诊断。

Else 的博客 1265

[Android 笔记九]Handler机制概念理解+多线程通信Demo

https://blog.youkuaiyun.com/carson_ho/article/details/80305411 主要概念: Handler:快递员(属于某个快递公司的职员) Message:包裹(可以放置很多东西的箱子) MessageQueue:快递分拣中心(分拣快递的传送带) Looper:快递公司(具有处理包裹去向的管理中心) 理解: 某时,你想刷新主界面的TextView,无奈你不在主线程,此时你就会包装好Message,然后声明一个Handler,让Handler将你的Message

weixin_38423311的博客 296

最新Anaconda3的安装配置及使用教程(详细过程)

最新Anaconda3安装使用Anaconda下载方式一:官网下载方式二:清华镜像下载(推荐)Anaconda安装 Anaconda是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项 Anaconda + Jupyter 基本上已经是大部分机器学习/数据分析等开发者标配的开发环境, 不多介绍,直接进去正题: Anaconda下载 方式一:官网下载 下载地址传送门: 官网首页:https://www.anaconda.com/ 官网下载页:https://www

HowieXue 薛永浩的博客 34万+

把 ABAP 经验装进 GitHub Copilot 的按需大脑,Agent Skills 如何改变 ABAP 开发

2026 年 8 月,SAP Community 上出现了一次很有代表性的 ABAP 实验。开发者把标准 Flight Model 里的复制成自己的测试类,删除原有 ABAP Unit Test,再让 GitHub Copilot Agent 为方法重新生成测试代码。真正有意思的地方并不是 Copilot 会不会写,而是开发者给 Copilot 准备了两个专门的 Agent Skills,一个负责 ABAP Unit Test 的通用规则,一个负责 ABAP Test Double Framework。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 152

Android多线程(三)——消息机制Handler的使用与源码解析

简介 handler是Android中的一种异步通信机制。因为Android不能在子线程中更新UI,当我们子线程执行异步任务时需要更新UI,这就可以使用在主线程中new Handler实例,在子线程中获取handler,实例使用sendMessage或者post方法通知主线程去更新UI。 使用 handler的应用很广,平时我们自己的继承Thread、实现Runable接口实现异步通信时都会使...

whale的博客 502

2024年全国青少年信息素养大赛复赛真题(算法创意实践挑战赛C++试卷:带解析)

2024年全国青少年信息素养大赛复赛真题(算法创意实践挑战赛C++试卷:带解析)

王老师青少年编程 4784

最全字节跳动技术整理:进程间的通信-之-Handler机制(1),2024年最新作为一名android面试者你应该知道的知识点

具体使用// 与方式1的使用不同:此处无复写Handler.handleMessage()源码分析/**源码分析:Handler的构造方法作用:a. 在此之前,主线程创建时隐式创建Looper对象、MessageQueue对象b. 初始化Handler对象、绑定线程 & 进入消息循环此处的源码分析类似方式1,此处不作过多描述*/工作流程类似,区别在于1、Handler.post不需外部创建消息对象,而是内部根据传入的Runnable对象封装消息对象。

2401_84538544的博客 709

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

android的消息处理机制(图+源码分析)——Looper,Handler,Message

我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想。android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种helper类,对于和我一样渴望水平得到进阶的人来说,都太值得一读了。这不,前几天为了了解android的消息处理机制,我看了Looper,Handler,Message这几个类的源码,结果又一次被googler的设计震撼了,

cold__v__moon的专栏 365

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Android异步消息阻塞,Android开发中的Handler异步通信传递机制

前言最近刚好在做关于异步通信的需求,那么,今天我们来讲解下Android开发中的Handler异步通信传递机制(包括Looper、Message Queue)目录定义Android提供的一套消息传递机制作用用于实现子线程对UI线程的更新,实现异步消息的处理:- 在新启动的线程中发送消息- 在主线程中获取并处理信息为什么要用Handler在安卓开发中:- 为了保证Android的UI操作是线程安全的...

weixin_33249310的博客 550

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Android的消息处理机制(图+源码分析)——Looper,Handler,Message

作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想。android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种helper类,对于和我一样渴望水平得到进阶的人来说,都太值得一读了。这不,前几天为了了解android的消息处理机制,我看了Looper,Handler,Message这几个类的源码,结果又一次被g

145

Android:Handler消息机制(二)——如何使用Handler消息机制

一、消息机制的工作步骤 Handler的工作流程分为四个步骤异步通信准备、消息发送、消息循环、消息处理: 1.异步通信准备:在主线程中创建处理器对象、消息队列对象、Handler对象,Looper和MessageQueue均属于主线程,在创建MessageQueue后Looper自动进入消息循环,此时Handler自动绑定主线程的Looper、MessageQuene,并且启动子线程 2.消...

ZytheMoon的博客 525

分析Handler的流程--源码系列

Handler的源码分析总结 1 Handler 简介 UI 线程里的操作要更新 UI 时,可以传递消息到主线程,主线程根据需求来更新 ui,可以避免线程操作不安全。 2 主要步骤 异步通信准备 消息发送 消息循环 消息处理 2.1 流程图 2.2 基本使用 //继承Handler类 & 复写handleMessage() class workHandler extends Handler { @Override public void han.

weixin_40119478的博客 299

Handler的消息处理

转载自:http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html 作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想。android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种helper类,对于和我一样渴望水平

crazy_yyyyy的专栏 963

Android的消息处理机制:Message、Handlerhe和Looper的图解及其源码解析

Android的消息处理机制:Message、Handlerhe和Looper的图解及其源码解析   (2012-06-14 11:01:06) 转载▼ 标签:  it 分类: Android博文精选 android的消息处理有三个核心类:Looper,Handler和Message。其实还有一个Message Queu

emerald0106的专栏 546

android的消息处理机制(图+源码分析)——Looper,Handler,Message+10

下摘自cheng330301560的android的消息处理机制(图+源码分析)——Looper,Handler,Message 符链接http://www.eoeandroid.com/thread-305698-1-1.html 学习android的一大乐趣是可以通过源码学习google大牛们的设计思想。android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们

dennyWang的专栏 764

安卓软件开发!你所不知道的Android原生开发的现状,附超全教程文档

前言: 笔者出生在江西一个偏远的山村。虽然出生时已经不是那个温饱都是问题的年代,但是也谈不上有个幸福的童年。家里很穷。幼儿园并没有读,因为家里觉得花那个钱没有必要,小学才开始学拼音字母。我的童年,就是和我的姐姐弟弟在山中的梯田里放牛,抓泥鳅,割鱼草。 大学上的是北大青鸟,一个成人培训机构,没有学历。在深圳打拼了6年了,一直在一些小公司打转。年初疫情突然爆发,市场经济进入寒冬,我也被公司裁员了。 这也让我意识到,本身学历就不高,如果还不发奋让自己的技术更上一个层次的话,肯定是没有未来可言的。幸而有朋友在阿里任

chayel123的博客 935

android 同一个thread是否运行完才能再开启_Android异步消息处理机制解析

点击上方“Android技术杂货铺”,选择“标星”干货文章,第一时间送达!本文来自手指尖的按恋投稿,博客地址:https://blog.youkuaiyun.com/gaolh89/article/details/90814343Android异步消息处理机制主要是指Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程。本文将通过结合源码(api-28)...

weixin_31869569的博客 290

Android线程间异步通信机制源码分析

本文简单介绍了Android系统线程之间异步通信的机制,从源码的角度简单谈论了线程通信时的基本工作。其中未详细深入到messageQueue的具体管理操作,只是简单提及了message对象的回收,具体细节有空再补上。

juruiyuan111的专栏 929
上一篇: 安卓跨进程通信:Binder解析
下一篇: 安卓跨进程通信:Messenger、AIDL远程Service 使用
魔幻音
博客等级 码龄6年 16粉丝 202原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔幻音

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值