Android -- Handler消息机制简析

安卓中的消息循环机制Handler及Looper详解 我们知道安卓中的UI线程不是线程安全的,我们不能在UI线程中进行耗时操作,通常我们的做法是开启一个子线程在子线程中处理耗时操作,但是安卓规定不允许在子线程中进行UI的更新操作,通常我们会通过Handler机制来完成该功能,即当子线程中耗时操作完成后,在子线程中通过Handler向主线程发送消息,在主线程中的Handler的handleMessage方法中处理接受到的消息。这就是安卓中的消息机制,安 阅读详情

Android -- Handler消息机制简析


Android系统是消息驱动的。说到Android中的消息机制,就一定离不开这四个类:Handler、Message、Looper和MessageQueue,它们是Android消息机制的主要实现部分。我们首先先明确这四个类在消息机制扮演的角色,然后再一一对它们进行分析。
熟悉Android的同学应该知道了:
  1. Handler:消息的发送者;通过Handler对象可以将一个消息发送到某个线程所有的MessageQueue中
  2. Message:消息实体;通过Handler发送的消息对象
  3. Looper:一个消息循环,它为一个线程开启一个循环的消息队列
  4. MessageQueue:消息队列,在Handler机制中,一个线程只维护一个消息队列
Handler发送消息是发送到某个线程所持有的消息队列中,然后消息队列依据先进先出原则分别取出Message对象进行处理。那怎么能让线程能持有一个MessageQueue队列、并成为Looper线程呢?工作中,我们一般会这样做:
class MyThread extends Thread {
        public void run(){
            Looper.prepare();//1

            //...

            Looper.loop();//2
        }
    }
通过1、2两步,这个线程就成为了Looper线程。那这两步做了些什么呢?我们分别分析。
Looper.prepare():
/** 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()}.
      */
    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));
    }
    // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
sThreadLocal是Looper类的静态成员,类型是ThreadLocal。ThreadLocal对象在维护变量时,会为每个线程都维护一个副本;每个线程都只能持有自己的那一份,某个线程做修改操作也不会影响到其他线程持有的副本。Looper中这样实现,就保证了每个线程中只会有持有一个Looper对象。到这里可知,Looper::prepare()函数的作用就是为某个线程创建了一个Looper对象:
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);//在当前线程中创建消息队列
        mThread = Thread.currentThread();//当前的线程对象
    }
这里做了两件事:
  1. 为当前线程创建了一个消息队列,保存在Looper对象中
  2. 在Looper对象中保存了一份当前线程的对象
再看Looper::loop()函数的实现,它的作用就是启动了当前的MessageQueue:
/**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        final Looper me = myLooper();//sThreadLocal.get();从sThreadLocal获取自己的Looper对象
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;//获取当前线程的MessageQueue对象

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

		//开启一个死循环,不断地从queue中获得消息,并进行处理
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);//发送的消息对象为维护一个发送它的Handler的实例,调用该Handler的dispatchMessage()方法

            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();
        }
    }
在loop()函数中,我们会开启一个循环,不断地从消息队列中获取消息并进行处理。
当然我们也可以调用Looper.quit()函数停止当前的Looper线程:
    /**
     * Quits the looper.
     * <p>
     * Causes the {@link #loop} method to terminate without processing any
     * more messages in the message queue.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p class="note">
     * Using this method may be unsafe because some messages may not be delivered
     * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
     * that all pending work is completed in an orderly manner.
     * </p>
     *
     * @see #quitSafely
     */
    public void quit() {
        mQueue.quit(false);
    }
到此,线程就已经持有了消息队列;使线程成为Looper线程的分析就结束了。
线程成为Looper线程后,我们要向MessageQueue中添加消息才有意义,这就要靠Handler对象了。要使用Handler发送消息,我们首先要创建Handler对象;查看它的构造函数:
/**
     * Use the provided {@link Looper} instead of the default one.
     *
     * @param looper The looper, must not be null.
     */
    public Handler(Looper looper) {// 1
        this(looper, null, false);
    }

    /**
     * Use the provided {@link Looper} instead of the default one and take a callback
     * interface in which to handle messages.
     *
     * @param looper The looper, must not be null.
     * @param callback The callback interface in which to handle messages, or null.
     */
    public Handler(Looper looper, Callback callback) { // 2
        this(looper, callback, false);
    }

    /**
     * Use the {@link Looper} for the current thread
     * and set whether the handler should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    public Handler(boolean async) { // 3
        this(null, async);
    }

    /**
     * Use the {@link Looper} for the current thread with the specified callback interface
     * and set whether the handler should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param callback The callback interface in which to handle messages, or null.
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    public Handler(Callback callback, boolean async) { // 4
        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;
    }

    /**
     * Use the provided {@link Looper} instead of the default one and take a callback
     * interface in which to handle messages.  Also set whether the handler
     * should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param looper The looper, must not be null.
     * @param callback The callback interface in which to handle messages, or null.
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    public Handler(Looper looper, Callback callback, boolean async) { // 5
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
Handler有多个重载的构造函数,但最后都会调用到序号为4、5的多参的构造函数。从构造函数的实现我们可知,我们可以传入某个Looper,也可以使用当前线程默认的Looper;不同的Looper就代表着使用不同的MessageQueue。得到Handler对象后,我们就可以通过它来发送消息了。Handler中可以发送了两种类型的消息:一种是Runnable类型的,另一种是Message类型的。下面分别看一下这两种发送方式的实现过程。先看
    /**
     * Pushes a message onto the end of the message queue after all pending messages
     * before the current time. It will be received in {@link #handleMessage},
     * in the thread attached to this handler.
     *  
     * @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.
     */
    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
最后的调用:
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;//把该Message对象的target设为this,代表当前发送消息的Handler
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);//将msg按延迟时间插入到消息队列中
    }
再看发送Runnable的形式:
  /**
     * Causes the Runnable r to be added to the message queue.
     * The runnable will be run on the thread to which this handler is 
     * attached. 
     *  
     * @param r The Runnable that will be executed.
     * 
     * @return Returns true if the Runnable was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.
     */
    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;//赋值给Message::callback字段
        return m;
    }
可以看出,即使发送的是Runnable对象(代表某个任务),随后也会被封装成Message;最后将消息放进消息队列的过程两种形式是一致的。
Handler发送消息的过程我们也已经有了大致的了解,接下来就要看消息的处理过程了。
在讲Looper::loop()的时候,我们知道这时会开启一个循环,不断地从消息队列中获取消息,并交由对应的Handler去处理:
//开启一个死循环,不断地从queue中获得消息,并进行处理
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);//发送的消息对象为维护一个发送它的Handler的实例,调用该Handler的dispatchMessage()方法

            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();
        }
其中
 msg.target.dispatchMessage(msg);//发送的消息对象为维护一个发送它的Handler的实例,调用该Handler的dispatchMessage()方法
就是消息的处理过程了。之前我们交过,我们在发送消息的时候,其中一步就是会将Message::target字段设置为当前发送消息的Handler对象。到此,我们就知道,一个消息的处理过程就是调用对应Handler的dispatchMessage()函数:
/**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {//如果发送的是Runnable,消息发送过程中会设置callback字段
            handleCallback(msg);
        } else {
            if (mCallback != null) {//构造Handler对象时传入了CallBack对象时,走该分支
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);//Message消息处理分支
        }
    }
这里对Runnable和Message两种类型的消息处理做了区分。如果Handler发送的是Runnable,则:
    private static void handleCallback(Message message) {
        message.callback.run();
    }
最后调用的是该Runnable对象的run()方法
如果发送的Message,则:
    /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }
    
由我们创建Handler时覆盖的handleMessage(Message)函数处理。
如果mCallBack不为空,则表示我们在创建Handler时传入了CallBack参数,此时的处理也比较简单:
    /**
     * Callback interface you can use when instantiating a Handler to avoid
     * having to implement your own subclass of Handler.
     *
     * @param msg A {@link android.os.Message Message} object
     * @return True if no further handling is desired
     */
    public interface Callback {
        public boolean handleMessage(Message msg);
    }
调用CallBack对象的handleMessage()函数进行处理。
最后,Message比较简单;我们要注意的就是它提供的四个参数:
 /**
     * User-defined message code so that the recipient can identify 
     * what this message is about. Each {@link Handler} has its own name-space
     * for message codes, so you do not need to worry about yours conflicting
     * with other handlers.
     */
    public int what;

    /**
     * arg1 and arg2 are lower-cost alternatives to using
     * {@link #setData(Bundle) setData()} if you only need to store a
     * few integer values.
     */
    public int arg1; 

    /**
     * arg1 and arg2 are lower-cost alternatives to using
     * {@link #setData(Bundle) setData()} if you only need to store a
     * few integer values.
     */
    public int arg2;

    /**
     * An arbitrary object to send to the recipient.  When using
     * {@link Messenger} to send the message across processes this can only
     * be non-null if it contains a Parcelable of a framework class (not one
     * implemented by the application).   For other data transfer use
     * {@link #setData}.
     * 
     * <p>Note that Parcelable objects here are not supported prior to
     * the {@link android.os.Build.VERSION_CODES#FROYO} release.
     */
    public Object obj;
具体的作用可以参考源码注释。最后,我们获取Message对象时,不要盲目地去创建新的Message,而是优先考虑调用Message::obtain()获取,这样会节省系统资源,更高效。

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

相关推荐

Android Handler消息机制详解

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

u011532067的博客 1192

Handler post(Runnable runnable)和sendMessage(Message msg)的区别比较

先上Handler的源码看一下: [java] view plain copy /**       * Default constructor associates this handler with the {@link Looper} for the       * current thread.       *       * If t

专注Android开发 2580

Handler消息机制详解

转载请注明链接:http://blog.youkuaiyun.com/feather_wch/article/details/79263855 介绍Handler、Looper、MessageQueue、ThreadLocal和主线程ActivityThread等内容 Android的消息机制 版本:2018/2/6-1 Android的消息机制 消息机制概述 ThreadLocal 消息...

feather(猎羽) 2322

Android面试常客之Handler全解

前言:又到了一年一度的跳槽季,准备跳槽的你在关于Android面试方面的知识都完全掌握了吗?Android面试中经常被问到的知识——Android消息机制即Handler有关的问题你都能解释的清楚吗?如果你对Android消息机制比较模糊或者能够回答与Handler有关的问题但是不清楚其中的原理,那么你将会在本文得到你想要的答案。 阅读本文后的收货   阅读本文后你将会有以下收获:...

fnhfire_7030的博客 1万+

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

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

笔沫拾光 2114

深入分析Android Handler消息机制

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

nufuli123的博客 1586

Handler消息机制

Handler消息机制的作用: 将一个任务切换到指定线程中(handler所在线程)中运行,多用来在主线程中更新UI 由来: 首先android ui线程不是线程安全的,如果不同线程都去访问UI那么会出现不可预期的下效果; 那么同步呢?每个线程调用时都要判断锁,这样降低了UI访问的效率,体验较差; 所以某个版本后(这里查了源代码2.3.7还没有ViewRootImpl类,4.0.2源码中有Vie...

倒骑驴走着瞧的博客 478

CAN收发器TJA1145A休眠唤醒应用

TJA1145的唤醒工作原理主要依赖于其内部的唤醒机制和外部硬件的配合,主要涉及低功耗状态、选择性唤醒功能。TJA1145是一款CAN收发器,它支持多种工作模式,包括NormalStandbySleep等。在这些模式中,Sleep模式是最低功耗状态,而Normal模式则是最活跃的状态,其中Standby模式处于两者之间,允许一定的功能操作但功耗较低。TJA1145可以通过接收特定的唤醒源从Sleep或Standby模式唤醒到Standby或Normal模式。唤醒源的检测与处理。

radix关于mcu的博客,持续更新中... 5950

【Android】Handler消息机制

Android消息机制学习分享

m0_74448051的博客 1650

Ubuntu22.04上如何用Docker一键部署Ragflow+Ollama(附CUDA配置避坑指南)

本文详细介绍了在Ubuntu22.04系统上使用Docker一键部署Ragflow+Ollama的完整流程,特别提供了CUDA配置的避坑指南。从硬件兼容性检查、驱动安装到容器网络配置,手把手教你搭建本地化大模型环境,解决CUDA驱动冲突等常见问题,助力开发者快速构建AI应用开发平台。

weixin_26875109的博客 284

Uni-App推送踩坑实录:从云函数URL化到后台推送失效,我都经历了什么

本文详细记录了Uni-App开发者在接入uni-push 2.0时遇到的推送失效问题,从云函数URL化到后台推送失效的完整排查过程。通过系统化分析和与官方沟通,最终找到解决方案,并分享了预防措施与最佳实践,帮助开发者避免类似问题。

weixin_42552716的博客 487

Android Handler消息处理机制

消息处理机制本质:一个线程开启循环模式持续监听并依次处理其他线程给它发的消息。简单的说:一个线程开启一个无限循环模式,不断遍历自己的消息列表,如果有消息就挨个拿出来做处理,如果列表没消息,自己就堵塞(相当于wait,让出cpu资源给其他线程),其他线程如果想让该线程做什么事,就往该线程的消息队列插入消息,该线程会不断从队列里拿出消息做处理。

轻口味的专栏 3402

基于IC动态加权的机器学习多因子选股策略:从模型融合到实战回测

在量化投资领域,多因子选股模型通过挖掘市场数据中的有效信号来预测股票收益。其核心原理在于利用统计学与机器学习算法,从海量因子中识别出与未来收益具有稳定相关性的特征。这一技术的核心价值在于将主观投资决策转化为系统化、可重复的客观过程,从而在控制风险的前提下追求超额收益。其典型应用场景包括股票阿尔法策略构建、Smart Beta产品设计以及资产配置中的股票筛选环节。本文聚焦于如何通过信息系数(IC)这一关键指标,动态融合Ridge回归、MLP神经网络和随机森林等多个预测模型,构建一个能够自适应市场风格轮动的选股

weixin_34216614的博客 451

安卓消息机制之Handler基础知识

相信大家从网上也看到过Handler的代码解析,下面我将从我个人理解的角度,以尽量通俗易懂的语言带领大家对Handler的用法以及源码设计进行解读。

weixin_39330114的博客 1452

中小型微服务系统 硬件设备如何部署,QPS大概多少

作为一名合格的开发工程师,不仅仅要在前期开发阶段对业务和技术有深入了解,知道选用哪种合适的技术,业务如何拆分,还要思考后期线上环境,资源,延迟,性能等如何优化维护以及分布式系统一些线上生产的一些问题。 本篇主要针对之前了解的情况对硬件设备资源做一个简单的介绍: 首先分布式系统线上实践问题,我们应该对公司的流量,各个服务,网管,注册中心应该如何部署,部署多少台机器才合适,每台机器的配置如何,每天整体流量有多少,高峰期的请求量有多少,你的整体系统是否扛得住(注:很多公司现在直接使用K8S docker 实现

wangxuelei036的博客 1万+

杰理芯片外挂Flash音乐播放功能避坑指南(附FAT文件系统配置)

本文详细解析了杰理芯片外挂Flash实现音乐播放功能的技术要点与常见问题,包括硬件连接、SPI驱动配置、FAT文件系统烧录及音乐播放集成等关键环节。特别针对Flash选型、FAT文件系统配置等易错点提供实用解决方案,帮助开发者高效完成嵌入式音频系统开发。

yhn45678901的博客 833

【Android 消息机制】Handler

Android专题学习-Handler总结

studyForMokey的博客 984

【ComfyUI】【Nunchaku】【diffusers报错解决】秋叶整合包安装 Nunchaku 报错的解决方法

最近在折腾 AI 绘图时,我尝试在秋叶的 ComfyUI 整合包中安装 `ComfyUI-nunchaku` 插件(版本 0.3.3),结果启动后直接报错,提示无法从 `accelerate.utils.memory` 中导入 `clear_device_cache`,让我一度怀疑插件是否兼容。查阅了一堆 issue 和源码之后,总算找到了原因和解决方法。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 1856

Android之handler消息处理机制详解

介绍android中常见的handler消息处理机制,分析源码

qq_43800449的博客 4189

Linux ARM平台开发系列讲解(GPIO子系统) 2.3.2 GPIO子系统常用函数解析

1. 概述 该章节会记录一年常用的GPIO子系统常用函数,会更具情况不断更新 static inline int gpio_get_value(unsigned int gpio) 功能 :用于获取某个GPIO引脚上的值 gpio : gpio引脚号 返回值:非负值,得到的 GPIO 值;负值,获取失败。 static inline void gpio_set_value(unsigned int gpio, int value) static inline int gpio_cansleep(unsi

DSMGUOGUO的博客 668

船舶工程专业英语词汇.doc

船舶工程专业英语词汇.doc

Android 基于Handler 剖析消息机制

Android handler 处理消息机制是Android 系统、应用开发中一个十分重要的利器,可以简单、轻松的将事情异步分解处理。Handler 与Looper、MessageQueue、Message类紧密结合,实现了完整的消息机制。

私房菜 3823

2000-2021年地级市产业升级、产业结构高级化面板数据(含原始数据和计算公式)

2000-2021年地级市产业升级、产业结构高级化面板数据(含原始数据和计算公式)1、时间:2000-2021年2、范围:地级市3、指标:地区生产总值、第一产业增加值、第二产业增加值、第三产业增加值、第一产业占GDP比重、第二产业占GDP比重、第三产业占GDP比重、产业结构水平、产业整体升级、产业结构高级化4、来源:城市NJ、地方统计J5、计算说明:产业结构=第三产业增加值/地区生产总值产业结构整体升级=第一产业增加值占GDP比重*1+第二产业增加值占GDP比重*2+第三产业增加值占GDP比重*3产业结构高级化=第三产业增加值/第二产业增加值6、参考文献:干春晖.中国产业结构变迁对经济增长和波动的影响

Android的消息机制--Handler

Android handler原理解析

weixin_42277946的博客 2972

2025央国企AI+数智化转型研究报告.pdf

2025央国企AI+数智化转型研究报告

BFS算法详解[项目源码]

本文详细介绍了广度优先搜索算法(BFS)的基本概念、应用场景及其实现方法。BFS是一种用于遍历或搜索树或图的算法,从一个顶点开始,辐射状地优先遍历其周围较广的区域。文章通过走迷宫的例子说明了BFS在寻找最短路径中的应用,并提供了BFS的核心代码实现。此外,文章还通过两个LeetCode例题(Word Ladder和Word Break II)进一步展示了BFS的实际应用和解题思路。最后,文章总结了BFS的时间复杂度及其适用场景,指出BFS适合解决给定初始状态和目标状态,要求最短路径的问题。

Android消息机制-Handler

基本概述在Android开发中提到消息机制应该所有人都不陌生,但是估计也很少有人能把消息机制详细地说出个所以然来,我们在开发过程中,有很多技术痛点,就是明明很多时候我们在用的东西,我们却不知道是为什么,它具体是个什么东西,很多时候我们只在乎它如何被拿来用,而不去关心更深层次的东西,也许这就是初中级向上进阶的阻碍吧。还好,我意识到了这一点,尽力去了解更多事实的真相…一不小心说了这么多废话,言归正传吧。

戚继光的博客 1689

Android Handler 消息循环机制

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

w2064004678的博客 1386
上一篇: Android -- 系统进程Zygote的启动分析
下一篇: Android -- Vold机制简要分析
第一序列丶
博客等级 码龄11年 249粉丝 77原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值