Handler浅析

2024-08-29 07:58
文章标签 handler 浅析

本文主要是介绍Handler浅析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

Android中多线程经常会涉及到传递消息的问题,尤其是更新UI,众所周知,子线程是无法更新UI,这时候就要借助Handler的消息传递机制。


一、构成

  1. Message: 消息,Handler处理的对象
  2. Looper:每个线程都有自己的looper,他负责将消息分发给对应的Handler
  3. MessageQueue: 初始化Looper对象的时候,会生成MessageQueue,它管理着Message
  4. Handler: 发送和处理消息

二、实例

我们先来看一个实例:

public class MainActivity extends AppCompatActivity {MyThread mThread;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mThread = new MyThread();mThread.start();mThread.mHandler.sendEmptyMessage(0x01);}class MyThread extends Thread {public Handler mHandler;@Overridepublic void run() {//初始化Looper,并生成MessageQueueLooper.prepare();mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {//处理发送过来的消息}};//不断的循环获取消息,并分发消息,没有消息时推出循环Looper.loop();}}
}

三、源码分析

1.Looper

1.1 Loop.prepare()

    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));}//这个是ActivityThread类中使用的public static void prepareMainLooper() {prepare(false);synchronized (Looper.class) {if (sMainLooper != null) {throw new IllegalStateException("The main Looper has already been prepared.");}sMainLooper = myLooper();}}

我们来解析private static void prepare(boolean quitAllowed),sThreadLocal是ThreadLocal类型,它有set和get方法

ThreadLocal:线程本地存储空间,不同线程之间,不能互相访问

ThreadLocal.set(T value):
将数据存储到ThreadLocal

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

ThreadLocal.get():
从ThreadLocal中得到数据

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

1.2 Looper构造函数

    private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();}

从代码可以看出,MessageQueue是在Looper生成的

1.3 Looper.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;// 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();for (;;) {//获取消息Message msg = queue.next(); // might block//如果没有消息,就会退出// No message indicates that the message queue is quitting.return;}// This must be in a local variable, in case a UI event sets the loggerfinal Printer logging = me.mLogging;if (logging != null) {logging.println(">>>>> Dispatching to " + msg.target + " " +msg.callback + ": " + msg.what);}final long traceTag = me.mTraceTag;if (traceTag != 0) {Trace.traceBegin(traceTag, msg.target.getTraceName(msg));}try {//分发消息msg.target.dispatchMessage(msg);} finally {if (traceTag != 0) {Trace.traceEnd(traceTag);}}if (logging != null) {logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);}// Make sure that during the course of dispatching the// identity of the thread wasn't corrupted.final long newIdent = Binder.clearCallingIdentity();if (ident != newIdent) {Log.wtf(TAG, "Thread identity changed from 0x"+ Long.toHexString(ident) + " to 0x"+ Long.toHexString(newIdent) + " while dispatching to "+ msg.target.getClass().getName() + " "+ msg.callback + " what=" + msg.what);}//将消息放入消息池msg.recycleUnchecked();}}

1.4 dispatchMessage

上面Looper.loop()中有一行这样的代码:

msg.target.dispatchMessage(msg);

它的作用是分发消息,我们来看看它的具体实现:

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

从这方法可以很清楚的看到,调用顺序:


  1. 当msg的回调方法部位null,则回调msg.callback.run();
  2. 当Handler的mCallback成员变量不为null时,则回调方法mCallback.handleMessage(msg);
  3. 调用Handler的回调方法handleMessage(),该方法默认为空,Handler子类需要覆写该方法。

一般情况下我们用的是第三种方法,也就是Handler.handleMessage()

2.消息

发送消息有很多方法,我例举两个:post和sendEmptyMessage,不过他们最终调用的是MessageQueue.enqueueMessage()。

post:

    public final boolean post(Runnable r){return  sendMessageDelayed(getPostMessage(r), 0);}

sendEmptyMessage:

    public final boolean sendEmptyMessage(int what){return sendEmptyMessageDelayed(what, 0);}

enqueueMessage:

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);}

post方法里面有有一个Runnable,但是这并不是新开了一个线程,而是把消息加Handler所在线程的消息队列里

3.Handler

handler的构造函数为:
无参:

    public Handler(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());}}//必须先执行Looper.prepare(),不然mLooper会等于nullmLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}mQueue = mLooper.mQueue;mCallback = callback;mAsynchronous = async;}

Looper为当前线程的Looper

有参:

    public Handler(Looper looper, Callback callback, boolean async) {mLooper = looper;mQueue = looper.mQueue;mCallback = callback;mAsynchronous = async;}

可以指定Looper

4. MessageQueue

4.1 enqueueMessage

添加一条消息到消息队列,源码省略

4.2 removeMessages

移除制定条件的消息,源码省略

5. 消息池

类似于线程池,当消息池不为空时,直接从消息池中获取Message对象,而不是直接创建Message,提高效率。

消息池有两个重要的方法,分别为:obtain()和recycle()

5.1 obtain()

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

当sPool不为空,直接从头部获取一个消息,如果sPool为空,则重新创建一个消息

5.2 recycle()

    public void recycle() {if (isInUse()) {if (gCheckRecycle) {throw new IllegalStateException("This message cannot be recycled because it "+ "is still in use.");}return;}recycleUnchecked();}//将不再使用的消息加入消息池void recycleUnchecked() {// Mark the message as in use while it remains in the recycled object pool.// Clear out all other details.flags = FLAG_IN_USE;what = 0;arg1 = 0;arg2 = 0;obj = null;replyTo = null;sendingUid = -1;when = 0;target = null;callback = null;data = null;synchronized (sPoolSync) {if (sPoolSize < MAX_POOL_SIZE) {next = sPool;sPool = this;sPoolSize++;}}}

这篇关于Handler浅析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1117297

相关文章

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

(入门篇)JavaScript 网页设计案例浅析-简单的交互式图片轮播

网页设计已经成为了每个前端开发者的必备技能,而 JavaScript 作为前端三大基础之一,更是为网页赋予了互动性和动态效果。本篇文章将通过一个简单的 JavaScript 案例,带你了解网页设计中的一些常见技巧和技术原理。今天就说一说一个常见的图片轮播效果。相信大家在各类电商网站、个人博客或者展示页面中,都看到过这种轮播图。它的核心功能是展示多张图片,并且用户可以通过点击按钮,左右切换图片。

风暴项目个性化推荐系统浅析

风暴项目的主要任务是搭建自媒体平台,作为主开发人员的我希望把工作重心放在个性化推荐系统上。 目前风暴项目的个性化推荐是基于用户行为信息记录实现的,也就是说对于每条资讯,数据库中有字段标明其类型。建立一张用户浏览表,对用户的浏览行为进行记录,从中可以获取当前用户对哪类资讯感兴趣。 若用户第一次登陆,则按默认规则选取热点资讯做推荐,及所有资讯按浏览量降序排序,取前4个。另外,我考虑到后期可能有商业

webservice的安全机制2---handler实现

本节摘要:本节介绍使用handler的方式来实现webservice的IP地址的校验。   1.引言 前一节介绍了使用users.lst文件来实现webservice的用户名和密码的校验, 本节介绍使用webservice的handler来实现webservice的安全校验。 这里,不用用户名和密码来实现安全校验,换一种方式,采用IP地址校验的方式。 这里通过一个配置文件来控制是否打开

中国书法——孙溟㠭浅析碑帖《越州石氏帖》

孙溟㠭浅析碑帖《越州石氏帖》 《越州石氏帖》  是一部汇集多本摹刻的帖,南宋时期的会稽石邦哲(字熙明)把家藏的一些法书碑帖集中一起摹刻成的,宋理宗时临安书商陈思《宝刻丛编》有记載这部帖的目录。现在还存有宋代时拓的残缺本,大多是相传的晋朝唐朝的小楷,后人多有临摹学习,并以此版本重新摹刻。 (图片来源于网络) 图文/氿波整理

浅析网页不安装插件播放RTSP/FLV视频的方法

早期很多摄像头视频流使用的是RTSP、RTMP协议,播放这类协议的视频通常是在网页上安装插件。但现在越来越多的用户,对于网页安装插件比较反感,且随着移动设备的普及,用户更多的希望使用手机、平板等移动设备,直接可以查看这些协议的视频。那是否有什么方案可以直接网页打开RTSP、RTMP协议的视频,直接观看不用安装插件呢?而且对于摄像头的数据,尽可能低延迟的获取实时画面。  其实很多摄像头厂家也注意到

浅析c/c++中 struct的区别

(1)C的struct与C++的class的区别。 (2)C++中的struct和class的区别。 在第一种情况下,struct与class有着非常明显的区别。C是一种过程化的语言,struct只是作为一种复杂数据类型定义,struct中只能定义成员变量,不能定义成员函数(在纯粹的C语言中,struct不能定义成员函数,只能定义变量)。例如下面的C代码片断: 复制代码代码如下:

Netty源码解析4-Handler综述

Netty中的Handler简介 Handler在Netty中,占据着非常重要的地位。Handler与Servlet中的filter很像,通过Handler可以完成通讯报文的解码编码、拦截指定的报文、 统一对日志错误进行处理、统一对请求进行计数、控制Handler执行与否。一句话,没有它做不到的只有你想不到的 Netty中的所有handler都实现自ChannelHandler接口。按照输入

Flink Exactly-Once 投递实现浅析

本文作者:Paul Lin 文章来源:https://www.whitewood.me 随着近来越来越多的业务迁移到 Flink 上,对 Flink 作业的准确性要求也随之进一步提高,其中最为关键的是如何在不同业务场景下保证 exactly-once 的投递语义。虽然不少实时系统(e.g. 实时计算/消息队列)都宣称支持 exactly-once,exactly-once 投递似乎是一个已被解

烟道灰酸洗废水稀有金属铼回收工艺浅析

铼是一种重要的稀有金属,因其独特的物理和化学性质,在航空航天、电子工业、石油化工等领域有着广泛的应用。由于铼的稀有性和重要性,从烟道灰中回收铼的技术和方法成为了研究的热点。以下是几种主要的烟道灰回收铼技术: ●    化学溶解法:通过选择合适的化学溶剂,如硝酸、硫酸等强酸,以及过氧化氢等氧化剂,将含铼废弃物中的铼溶解出来。 ●    溶剂萃取法:利用有机溶剂从含铼废水中萃取铼,通过选择合适的萃取剂