Handler源码解析二------- Looper源码

Android源码解析——Handler、Looper与MessageQueue 目前已经更新的部分资料:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!return m;如果mCallback不为 null ,则通过该回调接口来处理消息,如果在初始化 Handler 对象时没有通过构造函数传入Callback回调接口,则交由方法来处理消息,我们一般也是通过重写 Handler 的方法来处理消息最后来总结下以上的内容。 阅读详情

Handler源码解析二------- Looper


Handler相关的线程处理,还有Looper、Message和MessageQueue,下面会一一介绍。

本篇介绍Looper的源码

分析的是android api23 的源码,先上全部源码,在一个一个方法介绍

/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Log;
import android.util.Printer;

/**
  * Class used to run a message loop for a thread.  Threads by default do
  * not have a message loop associated with them; to create one, call
  * {@link #prepare} in the thread that is to run the loop, and then
  * {@link #loop} to have it process messages until the loop is stopped.
  *
  * <p>Most interaction with a message loop is through the
  * {@link Handler} class.
  *
  * <p>This is a typical example of the implementation of a Looper thread,
  * using the separation of {@link #prepare} and {@link #loop} to create an
  * initial Handler to communicate with the Looper.
  *
  * <pre>
  *  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();
  *      }
  *  }</pre>
  */
public final class Looper {
    /*
     * API Implementation Note:
     *
     * This class contains the code required to set up and manage an event loop
     * based on MessageQueue.  APIs that affect the state of the queue should be
     * defined on MessageQueue or Handler rather than on Looper itself.  For example,
     * idle handlers and sync barriers are defined on the queue whereas preparing the
     * thread, looping, and quitting are defined on the looper.
     */

    private static final String TAG = "Looper";

    // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // guarded by Looper.class

    final MessageQueue mQueue;
    final Thread mThread;

    private Printer mLogging;

     /** 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));
    }

    /**
     * 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.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    /**
     * Returns the application's main looper, which lives in the main thread of the application.
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

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

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

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

    /**
     * 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 @NonNull MessageQueue myQueue() {
        return myLooper().mQueue;
    }

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

    /**
     * Returns true if the current thread is this looper's thread.
     */
    public boolean isCurrentThread() {
        return Thread.currentThread() == mThread;
    }

    /**
     * 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.
     */
    public void setMessageLogging(@Nullable Printer printer) {
        mLogging = printer;
    }

    /**
     * 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);
    }

    /**
     * Quits the looper safely.
     * <p>
     * Causes the {@link #loop} method to terminate as soon as all remaining messages
     * in the message queue that are already due to be delivered have been handled.
     * However pending delayed messages with due times in the future will not be
     * delivered before the loop terminates.
     * </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>
     */
    public void quitSafely() {
        mQueue.quit(true);
    }

    /**
     * Gets the Thread associated with this Looper.
     *
     * @return The looper's thread.
     */
    public @NonNull Thread getThread() {
        return mThread;
    }

    /**
     * Gets this looper's message queue.
     *
     * @return The looper's message queue.
     */
    public @NonNull MessageQueue getQueue() {
        return mQueue;
    }

    /**
     * Dumps the state of the looper for debugging purposes.
     *
     * @param pw A printer to receive the contents of the dump.
     * @param prefix A prefix to prepend to each line which is printed.
     */
    public void dump(@NonNull Printer pw, @NonNull String prefix) {
        pw.println(prefix + toString());
        mQueue.dump(pw, prefix + "  ");
    }

    @Override
    public String toString() {
        return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
                + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}";
    }
}

先看最上面的类注释

*
* <p>This is a typical example of the implementation of a Looper thread,
* using the separation of {@link #prepare} and {@link #loop} to create an
* initial Handler to communicate with the Looper.
*
* <pre>
*  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();
*      }
*  }</pre>

这是一个典型的子线程实现looper的例子,源码中就有的。

在继续看类的成员变量

/*
 * API Implementation Note:
 *
 * This class contains the code required to set up and manage an event loop
 * based on MessageQueue.  APIs that affect the state of the queue should be
 * defined on MessageQueue or Handler rather than on Looper itself.  For example,
 * idle handlers and sync barriers are defined on the queue whereas preparing the
 * thread, looping, and quitting are defined on the looper.
 */

private static final String TAG = "Looper";

// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper;  // guarded by Looper.class

final MessageQueue mQueue;
final Thread mThread;

private Printer mLogging;
这些中第一个是TAG,打log用的。

第二个sThreadLocal是个线程变量,这个Looper是基于线程的,每个线程有一个Looper对象,这个Looper其实是存储在线程里的线程变量中的。

第三个是 sMainLooper 主线程looper,这里没看到子线程有同样的表示,还是主线程有特权啊。

第四个mQueue 是每一个looper都对应一个消息队列,这里持有这个队列的引用

第五个mThread 是looper执行的当前线程

第六个那个是调试打日志用的,这里不具体介绍了

然后把这几个主要的成员变量使用的地方介绍一下:

 /** 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));
}
/**
 * Return the Looper object associated with the current thread.  Returns
 * null if the calling thread is not associated with a Looper.
 */
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}
上面这两处是引用sThreadLocal的地方。

第一个是静态方法,创建looper到时候调用的:Looper.prepare();这个就可以new出Looper来了

第二个是判断是否有这个sThreadLocal存在,注释中也介绍了,如果为null说明Looper没有和调用的线程关联上

下面继续介绍sMainLooper

/**
 * 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.  See also: {@link #prepare()}
 */
public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

/**
 * Returns the application's main looper, which lives in the main thread of the application.
 */
public static Looper getMainLooper() {
    synchronized (Looper.class) {
        return sMainLooper;
    }
}
这两个也是静态方法,其中调用prepare()方法,这里注解介绍了,是系统调用,不需要咱们来调用这两个方法,调用的话会报错

第二个是获得这个sMainLooper对象。

下面继续介绍

final MessageQueue mQueue;

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

        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();
    }
}
/**
 * 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 @NonNull MessageQueue myQueue() {
    return myLooper().mQueue;
}

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}
public void quit() {
    mQueue.quit(false);
}
public void quitSafely() {
    mQueue.quit(true);
}
/**
 * Gets this looper's message queue.
 *
 * @return The looper's message queue.
 */
public @NonNull MessageQueue getQueue() {
    return mQueue;
}
/**
 * Dumps the state of the looper for debugging purposes.
 *
 * @param pw A printer to receive the contents of the dump.
 * @param prefix A prefix to prepend to each line which is printed.
 */
public void dump(@NonNull Printer pw, @NonNull String prefix) {
    pw.println(prefix + toString());
    mQueue.dump(pw, prefix + "  ");
}
一共这么几个地方,

dump()方法就是调试日志用的。

getQueue()方法就是获得他的引用

quitSafely() 这个是安全退出

quit() 和退出,这两个的具体实现实在MessageQueue中,之后会介绍,这两个区别在退出时如果有任务没执行完成该如何处理。

Looper()这个是构造方法了,构造方法是privae的,以后写程序也可以考虑这种方式,用static的方法去new 这个对象。

在这个构造方法中new出这个MessageQueue,所以没有Looper都会对应一个MessageQueue和一个Thread。

之后是myQueue()方法      代码是  return myLooper().mQueue;

这个myLooper()实现是这样的

        public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

其实就是从线程中取出looper,然后从looper中取出mQueue,这个和那个getQueue()方法貌似得到的一样,只是从两个地方取的,目前没发现区别。

然后继续到了最主要的loop()方法

final Looper me = myLooper();
if (me == null) {
    throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}

前面是如果Looper为null就抛出异常了

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循环

for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
    // No message indicates that the message queue is quitting.
    return;
}
查询queue中是否有消息,没有就返回了

// 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);
这个msg是消息Message,从MessageQueue中获取到的,需要处理的。

这个target其实是handler,也就是调用了handler的dispatchMessage()讲这个消息处理掉了,这里不明白的可以看下上一篇的handler解析

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();
将消息回收了。

for循环结束,方法结束

然后继续看Looper类的成员变量

final Thread mThread;
看看他的引用的地方

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}
这个是私有的构造方法,前面介绍过了,讲mThread 引用为当前线程。

/**
 * Returns true if the current thread is this looper's thread.
 */
public boolean isCurrentThread() {
    return Thread.currentThread() == mThread;
}
看看是否为当前调用的线程

/**
 * Gets the Thread associated with this Looper.
 *
 * @return The looper's thread.
 */
public @NonNull Thread getThread() {
    return mThread;
}

从looper中获得线程的引用,程序代码判断处理用的。

@Override
public String toString() {
    return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
            + ") {" + Integer.toHexString(System.identityHashCode(this)) + "}";
}
toString()方法了,这个说明这个Looper和线程很近很近啊,其实一个一个线程只能有一个looper

这个类里的所有方法都介绍完了

这个类加上注释一共就282行。内容不多。





Handler 源码解析——Handler的创建 前言 Android 提供了Handler和Looper来来满足线程间的通信,而前面我们所说的IPC指的是进程间的通信。这是两个完全不同的概念。 Handler先进先出原则,Looper类用来管理特定线程内消息的交换(MessageExchange); 1、为什么会有Handler机制? 我们刚说Handler机制的主要作用是将某一任务切换到特定的线程来执行,我们做项目可能都遇到过AN... 阅读详情

相关推荐

Handler,Looper以及HandlerThread的解析

Handler,Looper以及HandlerThread的解析 本文为作者原创,转载请注明出处。公众号为 毛铜飞 欢迎关注 1.前言 之前在工作过程中,都是以写笔记的形式,记录一些开发中遇到的问题,以及平时学习的心德和成果。后来发现,写给自己看

mao7101的博客 712

Android多线程(二)消息处理机制---Handler、Message、Looper源码原理解析

在Android中UI操作不是线程安全的,只有UI线程才能修改UI,所以我们经常开启子线程去处理一些耗时的操作,然后通过Handler发送消息,在UI线程中接送消息并处理UI组件,一个典型的Handler写法如下: private Handler handler = new Handler(){ @Override public void handleMessage(Message msg)

leienaleisi的博客 435

Handler Looper Message原理浅析

Handler Looper MessageQueue 原理浅析 说到Andorid线程间通信最常见的就是Handler,Handler的原理是个大厂面试必问,可见其重要程度。本文在这里从源码角度浅析一下Handler,Looper和MessageQueue 1.从Looper开始 首先我们知道,Looper从字面理解就是轮子的意思。 Looper的源码很少,区区不到300行且大半都是注释。我们直接上代码: private Looper(boolean quitAllowed) { mQueue =

m0_62167422的博客 2391

深入源码解析Android中的Handler,Message,MessageQueue,Looper

本文主要是对Handler和消息循环的实现原理进行源码分析,通过分析源码的方式去探索Thread、MessageQueue、Looper、Message以及Handler的实现原理,并最终通过一张图的形式将它们之间的关系展示出来。

孙群 3万+

深入源码分析Handler 消息机制 、Looper、MessageQueue 消息同步屏障、IdleHandler、Message 复用

Handler 线程通信 基本使用 在Android 中Handler来实现,大多数都是用来实现,子线程中发送消息,到主线程中更新UI,下面是基本使用 // 步骤1:在主线程中 通过匿名内部类 创建Handler类对象 mHandler = new Handler(){ // 通过复写handlerMessage(),处理其他线程发来的消息 ...

薛瑄的博客 2096

ROS下UR+Realsense相机进行手眼标定

手眼标定主要是用来确定相机坐标系和机械臂坐标系之间的转换关系,从而实现后续的抓取等任务。

weixin_42157689的博客 7569

InterviewQuestion实战:Handler、Looper、MessageQueue源码解析

在Android开发中,Handler、Looper、MessageQueue构成了核心的异步消息处理机制,是保证UI线程不阻塞、实现组件间通信的关键。本文将从实战角度解析这三者的工作原理及源码实现,帮助开发者深入理解Android消息循环机制。 ## 一、Handler机制核心组件关系 Handler机制主要由**Handler**、**Looper**、**MessageQueue**和*

gitblog_00318的博客 664

PX4无人机实战:手把手教你用MAVROS实现Offboard模式(附避坑指南)

本文提供了一份详尽的PX4无人机Offboard模式实战指南,重点解析了如何通过MAVROS实现从仿真到实机的控制。内容涵盖硬件连接、串口权限设置、MAVROS配置、核心代码编写以及实机操作全流程,并附有详细的避坑指南和故障排查手册,帮助开发者快速掌握ROS与PX4飞控的集成开发。

weixin_29172201的博客 267

Handler机制-Looper源码解析

Handler机制-Looper源码解析 介绍 安卓中Handler框架处理消息,其中Looper类用来循环从MessageQueue类中获取消息,然后调用Handler进行消费.本文将基于安卓9.0代码带分析Looper的实现. Looper的构造函数 //构造方法是私有的,构造方法私有的,一般会有静态方法来常见实例. private Looper(boolean quitAllowed) { ...

yumodev 1727

人工势场法在自动驾驶避障中的实践与优化

本文深入探讨了人工势场法在自动驾驶避障中的核心原理与实践优化。通过解析引力与斥力模型,揭示了经典算法在局部最优和目标不可达等问题上的局限性,并重点介绍了改进斥力场函数、引入道路边界斥力及动态参数调整等关键优化策略,有效提升了该局部路径规划算法在复杂动态场景下的实用性与鲁棒性。

weixin_29208327的博客 925

支付宝支付(三):周期扣款实现注意细节

一、周期扣款实现说明 1、官方文档入口:https://opendocs.alipay.com/open/20190319114403226822/intro 2、根据官方文档说明,周期扣款有两种方式:先签约后代扣场景和支付后签约场景 3、周期扣款接入问题文档: a>https://opendocs.alipay.com/support/01rg24 b>https://opensupport.alipay.com/support/knowledge/50249/20160248753

新鲜雾霾的博客 5696

一个线程可以有几个Looper?几个Handler?从Looper.prepare()来看看关于Looper的一些问题

前言 之前我有篇文章里面写到了Android的消息机制,Handler发送消息的一些原理。链接如下: 从Handler.post(Runnable r)再一次梳理Android的消息机制(以及handler的内存泄露) 在消息机制里面,有一个非常重要的东西,那就是Looper,Looper的作用主要是从消息队列里面取出消息交给Handler处理,不过不仅限于此,在这里面还有很多东西值得我们去...

梦里梦到醒不来的梦 1万+

CarMaker快速入门

本合集是小明师兄推出的CarMaker汽车仿真,CarMaker无论是传统动力学、动力系统开发、底盘系统开发还是目前智能驾驶辅助系统及智能驾驶系统开发有着非常重要的作用,可以有效节省开发周期和开发成本,基于仿真快速实现算法开发和系统验证。...

小明师兄的博客 1万+

Android Handler,MessageQueue,Looper源码解析

本文主要针对Handler机制原理进行源码分析,如果对Android的Handler机制不熟悉的可以查看Android Handler机制。 总结来说,Handler是Android中引入的一种让开发者参与处理线程中消息循环的机制。那这种机制如果仅仅通过一个Handler是无法完成任务的,还需要Looper、MessageQueue、Thread等的协作才能完成这一整套的异步消息循环处理机制。这...

红日 954

T2T基因组组装实战指南:从数据到完整染色体

本文详细介绍了T2T基因组组装技术的实战指南,从测序数据选择到完整染色体组装的全流程。重点解析了ONT ultra-long和PacBio HiFi测序技术的优势,以及如何攻克端粒和着丝粒等重复区域的组装难题。通过具体案例和实用技巧,帮助研究人员实现从数据到完整染色体的高质量组装。

weixin_29292535的博客 845

[AI] 企业内网部署大模型的三种常见方案:从“能用”到“好用”的技术选型指南

企业内网部署大模型的三种方案解析:本地模型安全但门槛高,平台方案(如Dify)最平衡推荐,混合架构适合进阶需求。关键路径是渐进式演进,从快速验证到平台化建设,核心在于流程优化而非单纯选模型。数据安全、成本可控和工程落地能力是决策重点。

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 769

Android 14 Handler 源码解析

Handler 是一套 Android 消息传递机制。在多线程应用场景中,将子线程中需要更新 UI 的操作消息,传递到 UI 主线程,从而实现子线程通知 UI 更新最终实现异步消息处理。说白了是用于线程之间的通信。Handler主要有4个重要类:Handler、Message、MessageQueue、Looper。**Handler:**负责消息的发送和处理,子线程中使用 sendMessage() 发送消息;在handleMessage()中处理。

u010345983的博客 1613

YOLOv11改进 | 上采样篇 | YOLOv11引入CARAFE上采样

在本文中,我们提出了一个通用、轻量级、高效的特征重组算子CARAFE来实现这一目标.CARAFE有几个吸引人的特性:(1)大视场。(2)内容感知处理。到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv11改进有效涨点专栏,本专栏目前为新开的,后期我会根据各种前沿顶会进行论文复现,也会对一些老的改进机制进行补充,如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~大视场:不同于以往的方法(如双线性插值),CARAFE能够在更大的感受野内聚合上下文信息,从而捕获更丰富的语义信息。

tsg6698的博客 920

Android源码学习 Handler、Looper和MessageQueue

源码使用Android Q 知识储备 知道Handler是干什么的,怎么使用的就可以了,如果不会可以看度娘。 获取Handler的方法 以下方法为Google官方文档提供的说明 构造方法 说明 Handler() 默认构造函数将Handler与当前线程的Looper关联。 Handler(Handler.Callback callback) 构造函数将Handler与当前线...

木寸~ 1万+

NTscan扫描工具

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

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

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

Android消息机制完全指南:Handler、Looper、MessageQueue源码解析

Android消息机制是Android开发的核心基础,其中Handler、Looper和MessageQueue三者构成了线程间通信的基石。无论是UI更新、异步任务处理还是系统组件交互,都依赖于这套高效的消息循环系统。本指南将从基本概念到源码实现,全面解析Android消息机制的工作原理,帮助开发者深入理解其内部运作机制。 ## 一、Android消息机制核心组件 Android消息机制主要由

gitblog_00410的博客 459

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Handler、Looper、MessageQueue、Message解析

Handler、Looper、MessageQueue、Message解析Handler相关源码逻辑梳理Handler用法Message合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章...

archie_7的博客 471

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Handler、Looper、HandleThread、ActivityThread简介

1 Thread类 open class Thread : Runnable 线程是程序中的执行线程。 Java 虚拟机允许应用程序同时运行多个执行线程。 每个线程都有一个优先级。 具有较高优先级的线程优先于具有较低优先级的线程执行。 每个线程可能会,也可能不会被标记为守护进程。 当在某个线程中运行的代码创建一个新的 Thread 对象时,新线程的优先级最初设置为等于创建线程的优先级,并且当且仅当创建线程是守护进程时,它才是守护线程。 有两种方法可以...

优快云爱好者的独到见解 3929
上一篇: Handler源码解析
下一篇: Handler源码解析三------ MessageQueue源码
method_chen
博客等级 码龄15年 25粉丝 61原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

method_chen

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

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

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

打赏作者

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

抵扣说明:

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

余额充值