Android中利用Handler实现消息的分发机制(一)

Android Handler消息机制详解 Android应用程序是通过消息驱动实现的,因此,Handler机制对于Android应用程序的运行极其重要。 本文详细的介绍了Handler、Looper、MessageQueue、Message、ThreadLocal,内容较长,可以分部分进行学习。文章未详尽之处,欢迎交流,描述有误之处,欢迎指正。 点关注,不迷路;点收藏,你更强;点点赞,我心欢。 阅读详情

上一篇文章,我们讲到在调用Handler的sendMessage方法时,最终我们会进入到一个叫 sendMessageAtTime的方法,如下:

    public boolean sendMessageAtTime(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等变量跟方法,我们可以想到,在Handler的实现的机制中,一定存在着一个消息队列,而它存放了我们创建的众多消息(Message)对象。

从这里,我们就会开始去探寻隐藏在 Handler对象后面的那一些我们想知道的实现机制了。

首先,我们还是从 Handler的创建开始说起,在上一篇文章,我们是通过 new Handler的方法来创建的,代码如下:

    private Handler mHandler = new Handler() {

        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MSG_ID_1:
                Log.v("Test", "Toast called from Handler.sendMessage()");
                break;
            case MSG_ID_2:
                String str = (String) msg.obj;
                Log.v("Test", str);
                break;
            }
            
        }
    };

显然,我们要去看一下Handler的构造函数,如下:

    public Handler() {
        this(null, false);
    }

    public Handler(Callback callback) {
        this(callback, false);
    }

    public Handler(Looper looper) {
        this(looper, null, false);
    }
    
    public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
    }

   
    public Handler(boolean async) {
        this(null, async);
    }

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

        mLooper = 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;
    }
    
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

我们可以看到,真正实现的构造函数,其实只有下面两个,如下:

    public Handler(Callback callback, boolean async) {
        ....
    }
    
    public Handler(Looper looper, Callback callback, boolean async) {
        ...
    }

这两个的差别就在于是否有参数Looper,而Looper是一个线程相关的对象。

何谓线程相关的变量?就是线程间不能共享的对象,只在本线程内有作用的对象。

那么Looper对象的作用是什么?

从我个人的理解,Looper类就是对MessageQueue的封装,它主要做的是两件事:

1)构造Looper对象,初始化MessageQueue,我们可以从其构造函数看到:

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


显然,MessageQueue正是在创建Looper的时候初始化的。

我们还注意到,这个构造函数是private的,而它则是被Looper.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));
    }

可以看到,Loop对象被创建之后,会被放到ThreadLocal变量中,而ThreadLocal正是线程局部变量,这说明了关于Looper的一个特性:

每一个线程中都只能有一个Looper对象。

2)调用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(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

           ...

            msg.target.dispatchMessage(msg);

           ....

            msg.recycle();
        }
    }

从上面的代码中,我们可以看到,在一个无限循环中,会从MessageQueue中获得消息,然后通过msg.target.dispatchMessage(msg)方法调用,处理消息,最后将消息进行回收。

在这里,我们先不关心dispatchMessage方法,我们先跑一下题,看一下recycle方法里面做了什么事吧,如下:

    private static Message sPool;
    private static int sPoolSize = 0;

    private static final int MAX_POOL_SIZE = 50;

    /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     */
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
    
    public void recycle() {
        clearForRecycle();

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }

从上面的代码中,我们可以看到,Message对象本身有一个next的字段指向另外一个Message,也就是说,可以通过链表的方式将众多的Message给串起来,变成一个链表的消息池sPool。

而在这里,当调用recycle方法,就会将当前Message对象,先clearForRecycle之后,再添加到 sPool的头部中,而当我们通过Message的obtain方法的时候,我们其实也是从sPool中拿 出一个空的Message对象。

相信看到这里,大家就了解了上一篇文章中我说,为什么建议大家使用Message.obtain方法去获取消息对象了吧。

接下来,我们再回到正题上。

从上面关于Handler的创建和关于Looper的描述中,我们可以得出这样一个结论:

在每一个线程中,如果我们要创建Handler,那么此线程中就必须有一个Looper对象,而这个Looper对象中又封装了一个MessageQueue对象来对Message进行管理。

所以,如果我们要在一个新线程中使用handler的话,我们就必须通过调用Loop.prepare()方法,为此线程创建一个Looper对象,官方给出的代码如下:

  class LooperThread extends Thread {
      public Handler mHandler;
  
      public void run() {
          Looper.prepare();
  
          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };
  
          Looper.loop();
      }
  }

当然,只有理论当然是不行的,我们还是得通过一个例子来看一下具体的效果,如下:

public class MainActivity extends ActionBarActivity {

    private static final int MSG_ID_1 = 1;
    private static final int MSG_ID_2 = 2;

    class LooperThread extends Thread {
        public Handler mHandler;

        public void run() {
            Looper.prepare();
    
            mHandler = new Handler() {                
                public void handleMessage(Message msg) {
                    Log.v("Test", "Id of LooperThread : " + Thread.currentThread().getId());
                    switch (msg.what) {
                    case MSG_ID_1:
                        Log.v("Test", "Toast called from Handler.sendMessage()");
                        break;
                    case MSG_ID_2:
                        String str = (String) msg.obj;
                        Log.v("Test", str);
                        break;
                    }
                }
            };
            Looper.loop();
        }
    }
    

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Log.v("Test", "Id of MainThread : " + Thread.currentThread().getId());
        
        LooperThread looperThread = new LooperThread();
        looperThread.start();
        
        while(looperThread.mHandler == null){                        
        }
        
        Message message = Message.obtain();
        message.what = MSG_ID_1;
        looperThread.mHandler.sendMessage(message);

        Message msg2 = Message.obtain();
        msg2.obj = "I'm String from Message 2";
        msg2.what = MSG_ID_2;
        looperThread.mHandler.sendMessage(msg2);

    }
}

对应的结果如下:

10-27 16:48:44.519: V/Test(20837): Id of MainThread : 1
10-27 16:48:44.529: V/Test(20837): Id of LooperThread : 68421
10-27 16:48:44.529: V/Test(20837): Toast called from Handler.sendMessage()
10-27 16:48:44.529: V/Test(20837): Id of LooperThread : 68421
10-27 16:48:44.529: V/Test(20837): I'm String from Message 2

那其实在这里有一个问题,为什么我们平常可以直接去创建Handler对象,而不需要去调用UI线程的Looper.prepare和loop等方法呢?

当然,这肯定也是需要的,只是这一步是由Android系统帮我们做了,所以默认的主线程就不再需要去做这些初始化。

好了,这一篇文章,我们就了解了关于线程,Looper,Handler, MessageQueue 和 Message 等之间的一些关联,而主要是对于Looper对象的认识。

结束。

Android Handler 消息机制 每一个搞 Android 的对 Handler 应该都不陌生,网上大神的文章也是数不尽的。这篇文章是个人在学习 Handler 过程中的一些疑问的记录。 1. 什么是 Handler,有什么作用 Handler 首先是一个 java 类,定义在/frameworks/base/core/java/android/os/Handler.java。但一般提到 Handler 并不专指它自身,常用来代指 Android 中的消息处理机制,或者说线程间通信的工具,典型应用就是在子线程中更新 UI 线程。那么,很显然 阅读详情

相关推荐

Android消息机制源码解析(Handler)

Android消息机制,其实也就是Handler机制,主要用于UI线程和子线程之间交互。众所周知,一般情况下,出于安全的考虑,所有与UI控件的操作都要放在主线程及UI线程,而一些耗时操作应当放在子线程中。当在子线程中完成耗时操作并要对UI控件进行操作时,就要用Handler来控制。另外,Android系统框架内,Activity生命周期的通知等功能也是通过消息机制来实现的。本篇博文主要是想通过Han

笔沫拾光 2114

Android事件分发机制详解:史上最全面、最易懂

点击事件由哪个对象发出,经过哪些对象,最终达到哪个对象并最终得到处理。这里的对象是指Activity、ViewGroup、View事件分发过程由dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()三个方法协助完成经过上述3个问题,相信大家已经对Android的事件分发有了感性的认知,接下来,我将详细介绍Android事件分发机制。

w1142203475的博客 1万+

深入分析Android Handler消息机制

概述 Handler是Android消息机制的上层接口。通过它可以轻松地将一个任务切换到Handler所在的线程中去执行。通常情况下,Handler的使用场景就是 更新UI。 Handler的使用 在子线程中,进行耗时操作,执行完操作后,发送消息,通知主线程更新UI。 public class Activity extends android.app.Activity { private Handler mHandler = new Handler(){ @Override

nufuli123的博客 1586

Android- Handler封装工具类

自定义封装Handle异步发送、接收消息工具类,使用仅需两行代码

Pengyuan87的博客 1214

Android Handler的机制跟源码分析

不断循环执行 Looper.loop() ,从 MessageQueue 中读取 Message ,按分发机制将消息分发出去给目标处理(将 Message 发到 Handler.dispatchMessage 方法去处理)。上面讲到了新建Message推荐使用 obtain() ,因为可以有效的复用消息,其中里面复用的就是 sPool 变量,它是在Message回收的时候进行赋值的。在应用启动时,会执行 main() 方法, main() 会创建一个 Looper 对象,然后开启一个死循环,目的是不断从。

u011324501的专栏 943

Android源码——Handler机制(一)

Handler是Android消息机制的上层接口。Handler可以将一个任务切换到Handler所在的线程中去执行。通常情况下,Handler的使用场景就是更新UI。@Override@Override@Override// 耗时操作.....}).start();在子线程中,进行耗时操作,执行完操作后,发送消息,通知主线程更新UI。这便是消息机制的典型应用场景。我们通常只会接触到Handler和Message来完成消息机制,其实内部还有两大助手来共同完成消息传递。

tracy的博客 1235

android——Handler的封装(添加软引用)、handle不造成内存泄漏的示例、new匿名实例是否会造成内存泄漏或崩溃

it1、弱引用(如上)2、在ondestroy里面调用handler.removeCallbacksAndMessages(null);结束!!!!

wy313622821的博客 3304

电力电子技术(13)——大功率可控整流电路

目录引言2.6.1 带平衡电抗器的双反星形可控整流电路电路结构的特点接平衡电抗器的原因平衡电抗器使得两组三相半波整流电路同时导电的原理分析谐波分析2.6.2 多重化整流电路概述原理目标1)移相多重联结2)多重联结电路的顺序控制3重晶闸管整流桥顺序控制带平衡电抗器的双反星形可控整流电路(是多重化整流电路的重要形式之一)的特点:适用于低电压、大电流的场合。多重化整流电路的特点:绕组的极性相反的目的:消除直流磁通势如图所示,虽然两组相电流的瞬时值不同,但是平均电流相等而绕组的极性相反,所以直流安匝(电流*匝数)互

weixin_45589295的博客 1万+

Android中利用Handler实现消息的分发机制(零)

在之前一篇介绍AsyncTask的文章中,我们在最后讲到,AsyncTask是利用Handler的消息异步处理机制,将操作结果,利用Message传回主线程,从而进行UI线程的更新的。 而在我们日常的开发工作中,Handler也是我们经常使用的类之一,那么Handler的主要作用是什么? Handler 的主要作用就是对消息(消息可以是我们想做的一些UI更新,也可以是其他的一些不可见的操作,如操作数据库等)的异步处理机制,而相信大家都了解异步的概念。 简单地说一下: 1)从程序的角度来看,就是当执行某行代码

持剑 2402

基于淘宝商城用户购物行为数据分析系统

本文使用HIve+superset技术对阿里云天池提供的淘宝用户购物数据进行处理分析,得到有价值的信息并对平台提出有建设性意义的意见。

m0_51388399的博客 2819

基于STM32的工业设备状态监测系统

工业设备的预测性维护需求日益增长,本文设计了一款基于STM32的智能监测终端,可实时采集设备振动、温度、电流等关键参数,通过边缘计算分析设备健康状态,实现故障预警与能效优化。系统支持4G/LoRa远程通信,适用于工厂、发电站等工业场景。本系统实现了工业设备关键参数的实时监测,故障识别准确率达到92%。:STM32F429(带FPU,支持浮点运算)多参数联合判据(振动+温度+电流突变检测)ACS712电流检测模块(0-30A)FFT频谱分析(识别轴承故障特征频率)故障代码生成(支持16种预设故障类型)

stm32d1219的博客 1323

Android基础-消息分发机制

Android中的消息分发机制是一个复杂而精巧的系统,它确保了Android应用的高效运行和响应性。通过Handler、Looper、MessageQueue和Message等核心组件的协同工作,Android系统能够处理各种事件和消息,并在正确的时机和线程中执行相应的处理逻辑。这种机制不仅提高了系统的并发性能,还降低了线程间通信的复杂性。

层楼终究误少年 1084

如何用Python+Librosa实现轴承异响检测?5步搞定工业设备故障预警

本文详细介绍了如何利用Python和Librosa库,通过5个步骤构建工业轴承异响检测与故障预警系统。从音频采集、预处理、频谱特征提取,到构建机器学习模型并进行实时监测,提供了完整的代码级解决方案。该方法能有效识别轴承早期故障特征,实现低成本、高效的设备预测性维护。

rnn9storyteller的博客 632

Study on Android【六】--消息机制,异步和多线程

有了framework后,我们不用面对赤裸裸的OS API,做一些重复而繁杂的事情。但天下没有免费的午餐,我们还是需要学会高效正确的使用不同的framework,很多处理某一特定问题的手法在不同的framework中,用起来都会有所不同的。 在Android中,下层是Linux的核,但上层的java做的framework把这一切封装的密不透风。以消息处理为例,在MFC中,我们可以用PreTran...

weixin_33796205的博客 68

别再乱选保护板了!手把手教你用ABLIC S-8254A为3/4串锂电池组DIY安全保护电路

本文详细介绍了如何使用ABLIC S-8254A保护集成电路为3/4串锂电池组DIY安全保护电路。从选型策略、电路搭建到功能验证,手把手教你实现可靠的充放电保护系统,适用于无人机、电动工具等场景,确保锂电池组的安全使用。

weixin_42525264的博客 188

【论文笔记】LIME: low-light image enhancement via illumination map estimation

【论文笔记】LIME: low-light image enhancement via illumination map estimation 一篇低光图像增强,引用超1000次的经典论文

weixin_45565519的博客 1793

Android的消息机制--Handler

Android handler原理解析

weixin_42277946的博客 2972

知识图谱大模型系列之 12 LLM 知识图谱构建器:从零到 GraphRAG 使用 LLM 知识图谱生成器在 GenAI 应用中提取和使用知识图谱(教程含源码)

为了更深入地了解 LLM 知识图谱构建器,GitHub 存储库提供了大量信息,包括源代码和文档。此外,我们的文档提供了详细的入门指南,而GenAI 生态系统则提供了有关可用更广泛工具和应用程序的进一步见解。

iCloudEnd的博客 2037

【Android 消息机制】Handler

Android专题学习-Handler总结

studyForMokey的博客 984

Python爬虫实战:高效爬取中国专利数据库的完整指南

在当今信息爆炸的时代,专利数据作为技术创新的重要指标,对企业研发、市场分析和学术研究都具有极高价值。中国作为全球专利申请量最大的国家,其专利数据库包含了海量的技术创新信息。本文将详细介绍如何使用Python最新技术构建一个高效、稳定的中国专利数据库爬虫系统。中国专利数据库主要由国家知识产权局(CNIPA)维护,包含发明专利、实用新型专利和外观设计专利三大类。截至2023年,中国专利数据库已收录超过400万件发明专利和300万件实用新型专利。

2201_76125261的博客 1572

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Android面试:Handler消息机制

消息的起点是Message对象,它承载了需要传递的消息,可以通过Message.obtain()获取一个Message对象(也可以使用Handler.obtainMessage()直接通过Handler获取一个Message对象);然后Handler通过sendMessage(Message msg)发送一个完整的Message对象到MessageQueue队列中(先进先出的队列,负责存储所有有待处理的消息),其内部会调用MessageQueue.enqueueMessage将消息按时间顺序插入队列;

aldkdb的博客 1331

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Android Handler 消息循环机制

核心思想:利用 Linux 的epoll机制,在无事可做时让线程进入休眠,在有新消息时能及时唤醒,从而兼顾了响应效率和资源消耗。

w2064004678的博客 1386

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Android中利用Handler实现消息的分发机制(三)

说到代码的可读性,有时候,我们更加看重代码之间的层次或者说模块化,耦合度等特点。 不同的业务逻辑,不同的功能,应该实现在不同的模块中,而模块与模块之间就可以通过一个消息来通信,而这种消息通讯方式,我们就可以利用Handler和HandlerThread来实现。 比如,最近做的一个浏览器的小Demo,其类图如下: ... 在不同的模块实现中, 我们可以调用registerHandler方法,将其对象的Handler注册到MessageDispatcher中,然后通过sendMessage方法,指定对应的目标,

持剑 2305

Handler消息机制-Handler

Handler 消息处理机制主要由 Handler、Looper、MessageQueue 和 Message 四部分组成。Handler作用:用于发送消息和处理消息。发送消息到 MessageQueue。处理从 Looper 分发的消息。特点:每个 Handler 绑定到一个 Looper,从而绑定到一个线程。可以发送 Message 或 Runnable。Message作用:消息的载体,封装了需要处理的任务或数据。通过 what 字段标识消息类型。通过 obj 字段传递数据。

只想搞钱 1719

Android-Handler消息机制

Handler 是 Android 中用于线程间通信的一种机制。在 Android 应用开发中,由于 Android 系统的单线程模型(主要是 UI 线程模型),为了避免在非 UI 线程中直接操作 UI 而导致程序异常(如 “Only the original thread that created a view hierarchy can touch views”),需要通过 Handler 来实现在不同线程之间传递消息,从而安全地更新 UI 或者执行其他跨线程的操作。

weixin_61662736的博客 1965

Android消息机制

以上便是消息机制的原理及组件解析,消息机制的运行过程,可以简单地用下图来理解。

weixin_58719774的博客 2055
上一篇: Android中利用Handler实现消息的分发机制(零)
下一篇: Android中利用Handler实现消息的分发机制(二)
linmiansheng
博客等级 码龄20年 507粉丝 111原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值