Android Looper和Handler分析

ImageReader相关函数分析 一、前提知识: App中的一个surface对应SufaceFlinger中的一个layout,surface需要申请GraphicBuffer来绘制UI内容,然后交给SurfaceFlinger去合成,然后显示;ImageReader中获得的image,也就是GraphicBuffer,用于绘制surface中的UI。 应用层经常会搭配如下两个函数来获取camera数据: mImageReader = ImageReader.newInstance(1920, 1080, ImageF... 阅读详情
第一次接触android应用程序(这里指的是JAVA层的UI程序,也难怪了,Google放出的API就只支持JAVA应用程序了),很难搞明白内部是如何实现的。但是,从原理上分析,应该是有一个消息循环,一个消息队列,然后主线程不断得从消息队列中取得消息并处理之。

然而,google封装得太厉害了,所以一时半会还是搞不清楚到底是怎么做的。本文将分析android内的looper,这个是用来封装消息循环和消息队列的一个类,handler其实可以看做是一个工具类,用来向消息队列中插入消息的。好比是Windows API的SendMessage中的HANDLE,这个handle是窗口句柄。

//Looper类分析
//没找到合适的分析代码的办法,只能这么来了。每个重要行的上面都会加上注释
//功能方面的代码会在代码前加上一段分析
public class Looper {
   //static变量,判断是否打印调试信息。
    private static final boolean DEBUG = false;
    private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;

    // sThreadLocal.get() will return null unless you've called prepare().
//线程本地存储功能的封装,TLS,thread local storage,什么意思呢?因为存储要么在栈上,例如函数内定义的内部变量。要么在堆上,例如new或者malloc出来的东西
//但是现在的系统比如Linux和windows都提供了线程本地存储空间,也就是这个存储空间是和线程相关的,一个线程内有一个内部存储空间,这样的话我把线程相关的东西就存储到
//这个线程的TLS中,就不用放在堆上而进行同步操作了。
    private static final ThreadLocal sThreadLocal = new ThreadLocal();
//消息队列,MessageQueue,看名字就知道是个queue..
    final MessageQueue mQueue;
    volatile boolean mRun;
//和本looper相关的那个线程,初始化为null
    Thread mThread;
    private Printer mLogging = null;
//static变量,代表一个UI Process(也可能是service吧,这里默认就是UI)的主线程
    private static Looper mMainLooper = null;
    
     /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
//往TLS中设上这个Looper对象的,如果这个线程已经设过了looper的话就会报错
//这说明,一个线程只能设一个looper
    public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }
    
    /** Initialize the current thread as a looper, marking it as an application's main 
     *  looper. The main looper for your application is created by the Android environment,
     *  so you should never need to call this function yourself.
     * {@link #prepare()}
     */
 //由framework设置的UI程序的主消息循环,注意,这个主消息循环是不会主动退出的
//    
    public static final void prepareMainLooper() {
        prepare();
        setMainLooper(myLooper());
//判断主消息循环是否能退出....
//通过quit函数向looper发出退出申请
        if (Process.supportsProcesses()) {
            myLooper().mQueue.mQuitAllowed = false;
        }
    }

    private synchronized static void setMainLooper(Looper looper) {
        mMainLooper = looper;
    }
    
    /** Returns the application's main looper, which lives in the main thread of the application.
     */
    public synchronized static final Looper getMainLooper() {
        return mMainLooper;
    }

    /**
     *  Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
//消息循环,整个程序就在这里while了。
//这个是static函数喔!
    public static final void loop() {
        Looper me = myLooper();//从该线程中取出对应的looper对象
        MessageQueue queue = me.mQueue;//取消息队列对象...
        while (true) {
            Message msg = queue.next(); // might block取消息队列中的一个待处理消息..
            //if (!me.mRun) {//是否需要退出?mRun是个volatile变量,跨线程同步的,应该是有地方设置它。
            //    break;
            //}
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }
                if (me.mLogging!= null) me.mLogging.println(
                        ">>>>> Dispatching to " + msg.target + " "
                        + msg.callback + ": " + msg.what
                        );
                msg.target.dispatchMessage(msg);
                if (me.mLogging!= null) me.mLogging.println(
                        "<<<<< Finished to    " + msg.target + " "
                        + msg.callback);
                msg.recycle();
            }
        }
    }

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
//返回和线程相关的looper
    public static final Looper myLooper() {
        return (Looper)sThreadLocal.get();
    }

    /**
     * Control logging of messages as they are processed by this Looper.  If
     * enabled, a log message will be written to <var>printer</var> 
     * at the beginning and ending of each message dispatch, identifying the
     * target Handler and message contents.
     * 
     * @param printer A Printer object that will receive log messages, or
     * null to disable message logging.
     */
//设置调试输出对象,looper循环的时候会打印相关信息,用来调试用最好了。
    public void setMessageLogging(Printer printer) {
        mLogging = printer;
    }
    
    /**
     * Return the {@link MessageQueue} object associated with the current
     * thread.  This must be called from a thread running a Looper, or a
     * NullPointerException will be thrown.
     */
    public static final MessageQueue myQueue() {
        return myLooper().mQueue;
    }
//创建一个新的looper对象,
//内部分配一个消息队列,设置mRun为true
    private Looper() {
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }

    public void quit() {
        Message msg = Message.obtain();
        // NOTE: By enqueueing directly into the message queue, the
        // message is left with a null target.  This is how we know it is
        // a quit message.
        mQueue.enqueueMessage(msg, 0);
    }

    /**
     * Return the Thread associated with this Looper.
     */
    public Thread getThread() {
        return mThread;
    }
    //后面就简单了,打印,异常定义等。
    public void dump(Printer pw, String prefix) {
        pw.println(prefix + this);
        pw.println(prefix + "mRun=" + mRun);
        pw.println(prefix + "mThread=" + mThread);
        pw.println(prefix + "mQueue=" + ((mQueue != null) ? mQueue : "(null"));
        if (mQueue != null) {
            synchronized (mQueue) {
                Message msg = mQueue.mMessages;
                int n = 0;
                while (msg != null) {
                    pw.println(prefix + "  Message " + n + ": " + msg);
                    n++;
                    msg = msg.next;
                }
                pw.println(prefix + "(Total messages: " + n + ")");
            }
        }
    }

    public String toString() {
        return "Looper{"
            + Integer.toHexString(System.identityHashCode(this))
            + "}";
    }

    static class HandlerException extends Exception {

        HandlerException(Message message, Throwable cause) {
            super(createMessage(cause), cause);
        }

        static String createMessage(Throwable cause) {
            String causeMsg = cause.getMessage();
            if (causeMsg == null) {
                causeMsg = cause.toString();
            }
            return causeMsg;
        }
    }
}

那怎么往这个消息队列中发送消息呢??调用looper的static函数myQueue可以获得消息队列,这样你就可用自己往里边插入消息了。不过这种方法比较麻烦,这个时候handler类就发挥作用了。先来看看handler的代码,就明白了。


class Handler{
..........
//handler默认构造函数
public Handler() {
//这个if是干嘛用的暂时还不明白,涉及到java的深层次的内容了应该
        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对象
//如果本线程还没有设置looper,这回抛异常
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
//无耻啊,直接把looper的queue和自己的queue搞成一个了
//这样的话,我通过handler的封装机制加消息的话,就相当于直接加到了looper的消息队列中去了
        mQueue = mLooper.mQueue;
        mCallback = null;
    }
//还有好几种构造函数,一个是带callback的,一个是带looper的
//由外部设置looper
    public Handler(Looper looper) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = null;
    }
// 带callback的,一个handler可以设置一个callback。如果有callback的话,
//凡是发到通过这个handler发送的消息,都有callback处理,相当于一个总的集中处理
//待会看dispatchMessage的时候再分析
public Handler(Looper looper, Callback callback) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
    }
//
//通过handler发送消息
//调用了内部的一个sendMessageDelayed
public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
//FT,又封装了一层,这回是调用sendMessageAtTime了
//因为延时时间是基于当前调用时间的,所以需要获得绝对时间传递给sendMessageAtTime
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)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;
        if (queue != null) {
//把消息的target设置为自己,然后加入到消息队列中
//对于队列这种数据结构来说,操作比较简单了
            msg.target = this;
            sent = queue.enqueueMessage(msg, uptimeMillis);
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
        }
        return sent;
    }
//还记得looper中的那个消息循环处理吗
//从消息队列中得到一个消息后,会调用它的target的dispatchMesage函数
//message的target已经设置为handler了,所以
//最后会转到handler的msg处理上来
//这里有个处理流程的问题
public void dispatchMessage(Message msg) {
//如果msg本身设置了callback,则直接交给这个callback处理了
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
//如果该handler的callback有的话,则交给这个callback处理了---相当于集中处理
          if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
           }
//否则交给派生处理,基类默认处理是什么都不干
            handleMessage(msg);
        }
    }
..........
}

 讲了这么多,该怎么创建和使用一个带消息循环的线程呢?

//假设在onCreate中创建一个线程
//不花时间考虑代码的完整和严谨性了,以讲述原理为主。
....

... onCreate(...){

//难点是如何把android中的looper和java的thread弄到一起去。
//而且还要把随时取得这个looper用来创建handler
//最简单的办法就是从Thread派生一个
class ThreadWithMessageHandle extends Thread{
  //重载run函数
  Looper myLooper = null;
  run(){
  Looper.prepare();//将Looper设置到这个线程中
  myLooper = Looper.myLooper();
  Looper.loop();开启消息循环
}

 ThreadWithMessageHandle  threadWithMgs = new ThreadWithMessageHandle();
 threadWithMsg.start();
 Looper looper = threadWithMsg.myLooper;//
//这里有个问题.threadWithMgs中的myLooper可能此时为空
//需要同步处理一下
//或者像API文档中的那样,把handler定义到ThreadWithMessageHandle到去。
//外线程获得这个handler的时候仍然要注意同步的问题,因为handler的创建是在run中的
 Handler threadHandler = new Handler(looper);
 threadHandler.sendMessage(...)
}


}



...

好了,handler和looper的分析就都这了,其实原理挺简单的。


来源:http://blog.youkuaiyun.com/innost/article/details/6055793




Android 中Looper机制详解 在《Android 基于Handler 剖析消息机制》一文中,以 Handler 类为起点详细分析了异步通信,分析了Java 端Handler与LooperMessage之前的通信关系。框架如下:在Java 端的 Looper 中会创建一个 Java 端的 MessageQueue实例,并在loop() 函数中的死循环里通过 queue.next() 不停的获取监听到的下一个 Message,然后将其通过 dispatchMessage() 分发处理。详细看。 阅读详情

相关推荐

基于PID的定速巡航控制系统设计【MATLAB源码+Word文档】

本文详细介绍了定速巡航控制是一种车辆驾驶辅助系统,它能让驾驶者在高速或长途驾驶时,设定一个固定的车速,然后车辆会自动维持这个速度行驶,无需驾驶者持续踩油门。这大大减轻了驾驶者的疲劳,同时也提高了行驶的安全性。PID定速巡航控制系统是一种利用比例(Proportional)、积分(Integral)和微分(Derivative)控制算法来实现车辆定速巡航的先进系统。这种系统能够根据设定的速度,自动调整油门开度或制动力度,使车辆保持恒定的速度行驶。这种控制系统具有响应速度快、控制精度高、稳定性好等优点。

weixin_761237174的博客 1670

Android中的Thread, Looper和Handler机制

** * Demo描述: * Android异步消息机制分析(附图) * * ======================================================= * * 问题的引入: * 在子线程中直接调用Handler handler=new Handler()此时报错: * Can't create handler inside thread t

JHarden的博客 461

【速通版!语义通信基础与前沿学习计划】

🧠语义通信基础与前沿学习计划

dally2的博客 1412

一起来聊聊Android基础之Handler

一起来聊聊Android基础之Handler 标签(空格分隔): Android基础知识 Android开发 参考资料: Understanding Android Core: Looper, Handler, and HandlerThread 一起来聊聊Android基础之Handler 扯闲篇 Handler使用示例 Handler源码简析 构造方法Handler() L...

当初游的快了一点 498

告别License烦恼:手把手教你用VS Code+Cppcheck搭建免费的MISRA-C代码检查环境

本文详细介绍了如何使用VS Code和开源工具Cppcheck搭建免费的MISRA-C代码检查环境,帮助开发者规避商业工具的高额License费用。通过四步环境搭建和实战技巧,实现高效的代码静态检查,提升嵌入式开发的安全性和可靠性。

weixin_42523326的博客 248

关于并网继电器的继电器自检逻辑及实现方式

对于常规的光伏并网逆变器来说,继电器控制至关重要。继电器一般位于逆变电感后,共模电感前,用于将逆变电压与电网电压脱开,一般国外有双继电器的安规强制认证要求,国内目前只需要单继电器要求(后续应该会有双继电器要求,个人感觉)

weixin_29982209的博客 2615

Android之Handler、Looper、MessageQueue源码分析.md

概述 Android中的Handler、Looper、MessageQueue是用来解决线程间通讯问题的一种机制.介绍它们的文章非常多,这里做一些学习和整理,帮助自己理解,也希望能方便大家. 一句话 “Looper不断获取MessageQueue中的Message,然后由Handler来处理” 一张图 先记住一句话和一张图,对这三者有一个感性的认识,后面会介绍一个简单的demo,通过...

2514

从零开始:手把手教你做转录组与代谢组的联合分析(含R代码)

本文详细介绍了转录组与代谢组联合分析的全流程,包括数据准备、预处理、差异分析及可视化方法,并提供了实用的R代码示例。通过多组学整合分析,研究者可以更全面地理解生物过程,适用于疾病机制和药物开发等医学研究领域。

weixin_29306317的博客 438

Android源码分析--Handler和Looper机制详解

在Android系统中的应用程序,与Java的应用程序相同,都是靠消息驱动,简单的说就是:有一个消息队列,我们可以不断的向这个消息队列中添加消息,并从中取出消息,处理消息。Android中与此工作相关的主要是由Handler,Looper以及Message来完成。 Looper类:为一个线程运行着一个消息循环,内部有一个消息队列,每一个线程只允许最多存在一个Looper; Handler类:允许你向

Joe_c 的专栏 6859

华为OD机试 - 机器人活动区域(Java 双机位C卷 200分)

现有一个机器人,可放置于 M × N的网格中任意位置,每个网格包含一个非负整数编号。之后M行表示网格数值,每行N个数值(数值大小用k表示),数值间用单个空格分隔,行首行尾无多余空格。说明:图中绿色区域,相邻网格差值绝对值都小于等于1,且为最大区域,对应网格点数目为6。M、N、k均为整数,且1

学Java,找哪吒 916

基于3D相机的人体穴位识别与标注系统——完整Python实现方案

摘要 本文提出了一种基于3D相机的人体穴位识别与标注系统完整实现方案。系统采用Intel RealSense D435相机实时采集RGB-D数据,结合MediaPipe Pose模型进行人体33个关键骨骼点的三维姿态估计。通过建立穴位与骨骼关键点的映射关系,利用相机内参和深度信息将二维图像坐标转换为三维空间坐标。系统采用模块化设计,包含数据采集层、算法处理层、坐标转换层和可视化层,实现了穴位定位、三维坐标转换和点云可视化功能。关键技术包括:基于骨度折量法的穴位映射算法、深度图像到三维点云的转换方法,以及Op

AI的内部世界的博客 270

【安卓笔记】Handler,Looper,MessageQueue,Message源码分析

这篇文章将分析android中的消息机制。 通过上一篇文章,我们了解到: 每一个handler其实都绑定了一个线程(Thread)和消息队列(MessageQueue),消息队列中存放的是一堆待处理的消息,Looper通过一个loop方法不断从消息队列中获取到消息(Message)(先进先出的方式),执行消息队列的出队方法,然后该消息会通过自身绑定target(其实是一个handler

RowandJJ 2940

基于 Simulink 的三相四线制整流器在三相不平衡负载下的中点电位平衡控制实战教程。

本文介绍了三相四线制整流器在不平衡负载下的中点电位平衡控制方法。首先分析了中点电位漂移的物理机理和控制策略(零序电压注入)。接着详细讲解了Simulink建模步骤:搭建三相四线制主电路、设计平衡控制算法、实现PWM调制。通过对比有无平衡控制的仿真结果,验证了控制方法的有效性。最后提供了工程建议:零序注入需限幅、考虑中性线寄生电感影响、采用稳健的PI参数。该方案能有效抑制中点电位波动,保障三电平系统在不平衡工况下的稳定运行。

MHD0815的博客 60

Android应用程序消息处理机制(Looper、Handler)分析

Android应用程序是通过消息来驱动的,系统为每一个应用程序维护一个消息队例,应用程序的主线程不断地从这个消息队例中获取消息(Looper),然后对这些消息进行处理(Handler),这样就实现了通过消息来驱动应用程序的执行,本文将详细分析Android应用程序的消息处理机制。        前面我们学习Android应用程序中的Activity启动(Android应用程序启动过程源代码分析和A

老罗的Android之旅 11万+

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Android源码分析——Looper,Messagequeue,Message,handler初始化及handler机制简介

Handler机制算是我入门源码的第一节。看得比较仔细。体会较多。mark一下。 顺序:先科普一下Handler基本功,然后再细讲下源码 一、Handler目的: 目的:Handler机制来处理了子线程去更新UI线程控件问题。 二、handler关系图: 其实各种书籍上都有这么一张图。但是主要是学习源码,所以还是自己手画一张“流程图”。 三、handler知识点总结: (若以下总结都

haibo_bear的博客 2863

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Android 消息机制 - Handler, Looper, Message, MessageQueue 的源码分析

转载请注明本文出自 clevergump 的博客:http://blog.youkuaiyun.com/clevergump/article/details/50776596, 谢谢! 一. 前言 Android 的消息系统, 主要涉及到四个类: Handler, Message, MessageQueue 和 Looper. 而我们在日常开发中, 通常是将 Handler 对象定义在主线程中用于更新UI, 这样..

clevergump的专栏 2142

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Android Loop机制中Looper与handler详细分析

根据以上所说的关系,画一张图:结论:handler的消息分为:同步消息,异步消息,屏障消息。handler的消息发送:消息都发送到了和它绑定的Looper的队列中去了。那么queue一对一looper,looper一对多handler,looper对象保存在所在线程的ThreadLocal中。

jh035的博客 1684

通过源码简要分析之Android消息机制Handler、Looper、MessageQueue运行机制

           用了许久的Handler,对于Handler的使用确实是比较熟悉,但是具体内部是如何运作的,却只是模糊的。Handler发出的消息怎么到达MessageQueue?MessageQueue的数据怎么被轮循处理?Looper是怎么循环取MessageQueue的消息的。今天,通过在子线程中创建Looper的实例,以追溯源码的方式来分析这个流程,通过这种方式来理解Android...

慢行的狮子 759

Android中的Handler、Looper、Message简要分析

1、Looper Looper的构造方法:构造方法中创建了一个消息队列private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); } Loope

psply的博客 519

Android Handler工作流程分析(一)Looper篇

版本:Android11 前言 Handler是Android中的非常重要的消息机制,能够在线程之间传递消息,例如Android主线程中的操作都是通过主线程的Handler进行的。最近在参加面试的时候有问到Handler相关的知识,才发自己对于这一块知识理解不深,好多问题都无法答的很好。所以准备查看一遍Framework中相关的内容,查缺补漏,让自己能够更好的理解Android Handler机制。 问题点 在看源码之前先整理一遍问题点,带着问题查看源代码效率更高。大家在看文章时也可以先看一遍问题,如果问题

z404403的博客 2048

Android的消息循环机制 Looper Handler类分析

http://www.cnblogs.com/mengdd/p/3601294.html

idea1____的博客 330

Android 源码分析 —— Handler、Looper 和 MessageQueue

本系列文章在 https://github.com/mzlogin/rtfsc-android 持(jing)续(chang)更(duan)新(geng)中,欢迎有兴趣的童鞋们关注。 本篇原始链接:https://github.com/mzlogin/rtfsc-android/blob/master/0x004-handler-looper-messagequeue.md 书接上...

靠谱-ing 658

Android之的Looper与Handler分析(待)

Android中的Looper与Handler分析

姥姥教我学编程 764
上一篇: eclipse内存分析工具MAT浅谈(一)
下一篇: Android中实现滑动翻页—使用ViewFlipper
SpeedyCoder
博客等级 码龄14年 415粉丝 7原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值