深入理解 Android Handler

Android——Handler详解 1. 简介 Handler是一套 Android 消息传递机制 可以说只要有异步线程与主线程通信的地方就一定会有 Handler。 在多线程的应用场景中,将工作线程中需更新UI的操作信息 传递到 UI主线程,从而实现 工作线程对UI的更新处理,最终实现异步消息的处理 使用Handler消息传递机制主要是为了多个线程并发更新UI的同时,保证线程安全 2. 相关概念解释 Handler、Message、Message Queue、Looper Android消息机制: 以Handler的sendMes 阅读详情

一、引言

Handler 在安卓中的地位是不言而喻的,几乎维系着整个安卓程序运行的生命周期,但是这么重要的一个东西,我们真的了解它吗?下面跟随着我的脚步,慢慢揭开Hanler的神秘面纱吧!

本文将介绍Handler 的运行机制、MessageQueue、Looper 的关系,ThreadLocal,以及Handler 导致的内存泄漏问题


二、Handler 系统组成概览

在 Handler 的源码中,主要涉及以下核心组件:

  • Message:封装消息的数据结构。
  • MessageQueue:存储 Message 的队列,内部是单链表。
  • Looper:负责循环读取 MessageQueue 并分发消息。
  • Handler:对外提供 sendMessage()、post() 发送消息,并处理 MessageQueue 中的消息。

它们之间关系如下图所示:


三、Handler 的创建

当 Handler 被创建时,它会绑定当前线程的 Looper:

public Handler() {
    this(Looper.myLooper(), null, false);
}
public Handler(Looper looper) {
    this(looper, null, false);
}

最终调用:

public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async,
               boolean shared) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
    mIsShared = shared;
}
  • mLooper 通过 Looper.myLooper() 获取当前线程的 Looper。
  • mQueue 由 Looper 提供,确保所有 Handler 在同一个 Looper 线程内共享 MessageQueue。

重点:主线程默认初始化 Looper,但子线程默认没有,需要手动 Looper.prepare()。

如果一定要在子线程中使用,推荐使用 HandlerThread,比于手动创建 Looper,HandlerThread 封装了 Looper 的创建和管理逻辑,代码更加简洁,也更易于维护。同时,HandlerThread 有自己独立的消息队列,不会干扰主线程或其他线程的消息处理。


四、sendMessage() 如何发送消息

当我们调用 sendMessage() 时:

handler.sendMessage(msg);

实际上调用:

public boolean sendMessage(Message msg) {
    return sendMessageDelayed(msg, 0);
}

最终:

public boolean sendMessageDelayed(Message msg, long delayMillis) {
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

最终调用 enqueueMessage():

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this; // 绑定 Handler
    return queue.enqueueMessage(msg, uptimeMillis);
}
@UnsupportedAppUsage
/*package*/ Handler target;

也就是说 Message 引用了 Handler,这也为内存泄漏埋下伏笔


五、MessageQueue 插入消息

boolean enqueueMessage(Message msg, long when) {
    synchronized (this) {
        // 插入 MessageQueue
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }
    }
    return true;
}

enqueueMessage 方法负责将消息按照时间顺序正确地插入到单链表结构的队列中,按 when 进行排序。


六、Looper 如何处理消息

Looper.loop() 读取消息
public static void loop() {
    for (;;) {
        Message msg = queue.next(); // 取出消息
        //...
        msg.target.dispatchMessage(msg); // 交给 Handler 处理
    }
}
MessageQueue.next()
Message next() {
    // 检查消息队列是否已销毁,若销毁则返回 null
    if (mPtr == 0) return null;

    int nextPollTimeoutMillis = 0;
    for (;;) {
        // 若有超时时间,刷新 Binder 待处理命令
        if (nextPollTimeoutMillis != 0) Binder.flushPendingCommands();
        // 阻塞线程,等待新消息或超时
        nativePollOnce(mPtr, nextPollTimeoutMillis);

        synchronized (this) {
            final long now = SystemClock.uptimeMillis();
            Message msg = mMessages;
            // 若为屏障消息,找下一个异步消息
            if (msg != null && msg.target == null) {
                do { msg = msg.next; } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                // 若消息未到处理时间,计算超时时间
                if (now < msg.when) {
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // 若消息到处理时间,从队列移除并返回
                    mMessages = msg.next;
                    msg.next = null;
                    msg.markInUse();
                    return msg;
                }
            } else {
                // 若无消息,一直阻塞
                nextPollTimeoutMillis = -1;
            }
            // 若消息队列正在退出,释放资源并返回 null
            if (mQuitting) {
                dispose();
                return null;
            }
        }
    }
}

nativePollOnce() 让当前线程进入阻塞状态,直到有新的消息到来或者超时

nativePollOnce() 的主要功能是:

  • 线程阻塞:让当前线程进入等待状态,避免空转消耗CPU资源
  • 事件唤醒:当有新消息到达或超时发生时,立即唤醒线程处理
  • Native 层集成:与 Linux 的 epoll 机制对接,实现高效I/O多路复用
void nativePollOnce(long ptr, int timeoutMillis)

ptr:指向 Native Looper 对象的指针(C++对象地址)

timeoutMillis 的含义:

  • 如果 timeoutMillis > 0
    • epoll_wait 最多阻塞 timeoutMillis 毫秒,期间如果有事件发生,则提前返回。
  • 如果 timeoutMillis == 0
    • epoll_wait 立即返回(非阻塞)。
  • 如果 timeoutMillis < 0
    • epoll_wait 无限等待,直到有事件触发。

最终调用了 Linux epoll 机制 来监听消息事件。


七、nativePollOnce 方法调用流程

Java 层调用
// MessageQueue.java
private native void nativePollOnce(long ptr, int timeoutMillis);

JNI 本地方法,由 MessageQueue 调用,用于等待消息。

在 MessageQueue.next() 方法中:

// MessageQueue.java
nativePollOnce(mPtr, nextPollTimeoutMillis);

它的作用是:

  • 如果 MessageQueue 里有消息,立即返回。
  • 如果没有消息,则阻塞,直到有新的消息到来或 timeoutMillis 超时。
JNI 层调用
static void android_os_MessageQueue_nativePollOnce(JNIEnv* env, jobject obj,
        jlong ptr, jint timeoutMillis) {
    MessageQueue* mq = reinterpret_cast<MessageQueue*>(ptr);
    mq->pollOnce(timeoutMillis);
}

将 Java 传来的 mPtr 转换成 MessageQueue* 对象,并调用 pollOnce() 方法。

Native 层 pollOnce()

在 MessageQueue.cpp:

void MessageQueue::pollOnce(int timeoutMillis) {
    mLooper->pollOnce(timeoutMillis);
}

调用了 Looper::pollOnce(),进入 消息轮询 逻辑。

Looper 的 pollOnce()

在 Looper.cpp:

int Looper::pollOnce(int timeoutMillis) {
    return pollInner(timeoutMillis);
}

这里调用 pollInner(timeoutMillis),它的核心逻辑是 使用 epoll_wait() 监听事件。

epoll 监听消息事件

pollInner(timeoutMillis) 的核心逻辑:

int Looper::pollInner(int timeoutMillis) {
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

    if (eventCount > 0) {
        for (int i = 0; i < eventCount; i++) {
            // 处理事件
        }
    }
}

其中:

  • mEpollFd 是 epoll 文件描述符,用于监听多个文件描述符(FD)。
  • epoll_wait() 会 阻塞当前线程,直到:
    • 有 新消息可读
    • 有 文件描述符事件触发
    • 超时(timeoutMillis 毫秒后自动返回)

到这里,我们清楚了 nativePollOnce 的主要作用是等待新消息到达消息队列。当调用这个方法时,如果当前消息队列中没有需要立即处理的消息,线程会被阻塞,从而释放 CPU 资源,直到有新消息到来或者发生其他唤醒条件。

那么 epoll_wait() 如何监听消息?
epoll_wait() 监听哪些事件?

MessageQueue 的 pipe(管道):当 Handler 发送消息时,写入 pipe,触发 epoll 事件。

输入事件:当用户触摸屏幕或按键时,触发 epoll 事件。

文件描述符(FileDescriptor):例如 Binder 进程间通信(IPC)事件。

等等…

消息如何触发 epoll?
  • Handler.sendMessage() 会向 MessageQueue 写入数据:
void Looper::wake() {
    uint64_t inc = 1;
    ssize_t nWrite = write(mWakeEventFd, &inc, sizeof(uint64_t));
    // 错误处理省略...
}

具体调用在 MessageQueue.enqueueMessage(),会通过 nativeWake() 唤醒 Looper 的事件循环。

// MessageQueue.java
boolean enqueueMessage(Message msg, long when) {
    // ... 插入消息逻辑 ...
    if (mQuitting) {
        return false;
    }
    // 唤醒 Looper
    nativeWake(mPtr);
}

完整调用链:

Handler.sendMessage() 
→ MessageQueue.enqueueMessage() 
→ MessageQueue.nativeWake() (JNI)
→ NativeMessageQueue.wake() 
→ Looper.wake() 
→ write(mWakeEventFd, &inc, sizeof(uint64_t))
  • mWakeEventFd 是一个 eventfd 文件描述符,用于线程间唤醒(比 pipe 更高效)。
  • 写入的内容 是一个 uint64_t 的值。
  • 写入的时机 是当新消息被插入到队列头部,或队列原本为空时需要唤醒线程时。
  • epoll_wait() 监听到 pipe 有数据,返回。

  • Looper 处理新消息,Java 层 Handler 开始执行 handleMessage()。

epoll_wait阻塞等待wakeFd上的可读事件,当有数据写入wakeFd,epoll_wait返回,线程被唤醒,这里并不关心写入wakeFd的具体数据是什么,只关心可读事件的发生。

pipe 的作用

让 Handler.sendMessage() 触发 epoll 事件,立即唤醒 Looper。

至此,综上,我们可以知道 epoll_wait() 只负责等待事件,不会提前返回“第一条消息”,它只会返回“有事件触发”的信号,具体执行哪个消息是 MessageQueue.next() 的逻辑,它会选择最早应该执行的消息,这就是 Handler 的阻塞唤醒的核心逻辑所在!


八、Handler 处理消息

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        msg.callback.run();
    } else {
        handleMessage(msg);
    }
}

最终执行:

@Override
public void handleMessage(Message msg) {
    // 需要用户实现
}

九、核心组件之间的关系

Thread
  └── ThreadLocal<Looper>
        └── Looper
              └── MessageQueue
                    └── Message1 → Message2 → ...
                          ↑
                       Handler
  • Handler 持有对 MessageQueue 的引用(间接通过 Looper)因为Handler中的 MessageQueue 是从 Looper 中获取的;
    public Handler(@Nullable Callback callback, boolean async) {
        //..
        mQueue = mLooper.mQueue;
        //..
    }
  • 每个线程通过 ThreadLocal 绑定自己的 Looper;
  • Looper 管理其对应的 MessageQueue;

这样它们的关系就清晰了,每个线程只有一个Looper(是由ThreadLocal确保的),可以有多个Handler。

public final class Looper {
    // 线程本地存储,每个线程一个Looper实例
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

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

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

关于ThreadLocal的详细介绍可以看这篇文章:深入剖析Java中ThreadLocal原理


十、内存泄漏问题分析及解决方案

我们都知道判断内存泄漏的依据是:短生命周期对象是否被长生命周期对象引用!既然使用Handler不当会导致内存泄漏,那么我们只需要找到被引用的源头,然后去解决。

Handler 导致内存泄漏的完整引用流程
  • 匿名内部类或非静态内部类的隐式引用:

众所周知,在Java中 匿名内部类或非静态内部类会持有外部类的引用,如下:

public class MainActivity extends AppCompatActivity {
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // 处理消息
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler.sendEmptyMessageDelayed(0, 10000);
    }
}

这里的mHandler是一个非静态内部类。非静态内部类会隐式持有外部类(这里是MainActivity)的引用。这意味着mHandler对象中包含了对MainActivity实例的引用。

  • MessageQueue 对 Message 的持有:

在上面示例中,我们发送了一个延迟的Message,尽管只传了一个0,但是其内部也会封装为Message,这时候Handler 会将 Message对象并将其发送到与之关联的MessageQueue中,MessageQueue会持有这个Message对象,直到该消息被处理。

  • Message 对 Handler 的持有:

由上面第四小节的sendMessage()可知,在放入队列的时候,会将Handler 与 Message 关联:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this; // 绑定 Handler
    return queue.enqueueMessage(msg, uptimeMillis);
}

主要作用是,让Message知道是从哪个Handler发送的,并最终让那个Handler 的 handleMessage去处理。

public final class Looper {
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    @UnsupportedAppUsage
    private static Looper sMainLooper;  // guarded by Looper.class
    //...
}

我们都知道,在主线程中,主线程的Looper会一直运行下去(或者说 Looper被 静态 ThreadLocal<Looper> 所引用),不能被停止,而MessageQueue 又被Looper 所引用,这就产生了一条完整的引用链:ThreadLocal<Looper> - Looper - MessageQueue - Message - Handler - MainActivity

** 解决方案**
  • 使用静态内部类 + WeakReference:

要解决内存泄漏,就是把引用链上任意一条引用断开,让GC不可达就行了,其实我们能操作的就只有 Handler - **MainActivity **这一条引用:

static class MyHandler extends Handler {
    private final WeakReference<MyActivity> ref;
    MyHandler(MyActivity activity) {
        ref = new WeakReference<>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        MyActivity activity = ref.get();
        if (activity != null) {
            // Safe to use activity
        }
    }
}
  • 在 Activity 的 onDestroy() 中清除消息:
handler.removeCallbacksAndMessages(null);

其实,只要消息不是延迟很久或者反复堆积,就不会在 MessageQueue 中长时间滞留,从而也就不会延长 Handler 或其持有对象的生命周期。

想想,在实际开发中,谁会在Activity中延迟发送一个很长时间的消息,所以我们不必为 Handler 导致内存泄漏,过度紧张,稍微留意一下就可以避免了 😃


十一、最后

Handler 是 Android 消息机制的基础组成部分。通过对 Handler、Looper、MessageQueue 之间关系的理解,我们可以更深入掌握 Android 的线程模型与 UI 更新流程。

由于本人能力有限,并没有对 Handler 进行过度深入全面了解,比如同步屏障等,如果文章内容解读有误,还望不吝赐教。

Android Handler机制使用及全面解析 仅是个人对Handler机制的理解,通过翻看源码和其他大佬对源码的阅读理解对此做了总结,文中不足的是对于nativePollOnce这个native方法做的深入了解不够多。后面如果还有其他没总结到的再写进来。 阅读详情

相关推荐

一文带你深入理解Android-Handler机制(深入至native层)

epfd 表示epoll句柄 op 表示fd操作类型,有如下3种 EPOLL_CTL_ADD 注册新的fd到epfd中 EPOLL_CTL_MOD 修改已注册的fd的监听事件 EPOLL_CTL_DEL 从epfd中删除一个fd fd 是要监听的描述符 event 表示要监听的事件,事件可以使如下如下几种宏的集合 EPOLLIN :表示对应的文件描述符可以读 EPOLLOUT:表示对应的文件描述符可以写 EPOLLERR:表示对应的文件描述符发生错误; epoll_wait .

m0_66264798的博客 1063

Android——Handler一篇就看懂

Android handler的详细讲解

未来源起的博客 9698

深入理解Android Handler机制与实践

Handler是Android中用于处理线程间通信的类,它可以发送和处理Message和Runnable对象。Handler的主要功能包括:确保Message和Runnable对象的执行被分发到创建Handler的线程中。在不同的线程中进行数据的传递。实现复杂的线程间通信逻辑。一个典型的使用场景是在非UI线程中处理耗时任务,完成后再通过Handler更新UI线程。是Handler类的核心方法,用于处理从消息队列中取出的Message对象。该方法在。

weixin_30336531的博客 1072

Android中Handler介绍

首先点击按钮会触发start函数,在start函数中创建了一个子线程,在子线程中创建消息的内容,即在getStringFromNet()中输入字符串,为了看到效果(子线程只执行run()中的代码,外面的代码都在主线程中执行),睡眠了三秒,之后使用sendMessage()将消息发送到Messagequeue中,随后主线程中使用handleMessage()去Messagequeue中取消息,最后将消息显示出来。如果队列中没有同步屏障,则返回队列中的同步消息,并将该同步消息从队列中移除。

sky_1305995351的博客 4038

单细胞分析避坑指南:你的Harmony批次矫正真的做对了吗?

本文深入探讨了单细胞转录组分析中Harmony批次矫正的正确使用方法,解析了其工作原理及常见误区。通过详细参数调优指南和实战案例,帮助研究者避免过度矫正,确保生物学信号的有效保留。特别关注Harmony在单细胞数据分析中的关键参数设置和结果验证方法。

weixin_31099291的博客 298

什么是Merkle树?用“文件柜”类比理解区块链的核心技术

Merkle树是一种用于区块链的数据结构,像一个高效的“文件柜”,用于存储和验证大量交易数据。比特币通过Merkle树将交易哈希组织成树状结构,层层汇总,最终生成一个唯一的根哈希,存储在区块头中。这种设计大幅减少数据存储和验证成本,支持快速校验交易的完整性和存在性。Merkle树通过密码学保证数据不可篡改,广泛应用于比特币、区块链及其他分布式系统。它的优势在于高效、轻量和安全,尤其适合轻节点验证和数据同步。理解Merkle树就像掌握区块链的“索引秘籍”,是Web3世界的关键技术。

在路上的专栏 1192

深入理解之 Android Handler

一,相关概念 在Android中如果通过用户界面(如button)来来启动线程,然后再线程中的执行代码将状态信息输出到用户界面(如文本框),这时候就会抛出以下的异常信息: 5-12 13:33:04.393: ERROR/JavaBinder(1029):android.view.ViewRoot$CalledFromWrongThreadException:Onlythe original

紫璐宇的专栏 1万+

从M.2到E1.S,从U.2到E3.S:数据中心SSD接口的世代更迭与选择逻辑

本文深入探讨了数据中心SSD接口从M.2、U.2到E1.S、E3.S的演进历程与选型逻辑。通过对比分析不同接口的物理规格、性能表现和散热设计,揭示了EDSFF接口在数据中心环境中的优势,包括更高的部署密度、更好的散热效能和更强的扩展能力。文章还提供了针对不同应用场景的SSD选型建议,帮助IT决策者优化存储架构。

weixin_33816300的博客 415

Handler——深入理解android消息机制

android 重要核心知识点,怎么深刻理解都不为过 常用api,主线程接收处理消息 private Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case 1 : ...

MrPeng的博客 739

PHP项目实战:易宝支付SDK对接全流程(含回调处理与常见问题排查)

本文详细介绍了PHP项目中易宝支付SDK的对接全流程,包括环境准备、SDK配置、支付请求构建与发起、回调处理实战以及常见问题排查。特别针对回调处理环节的常见问题提供了解决方案,帮助开发者快速完成支付对接并优化性能。

weixin_29007809的博客 386

UFAST车道线检测 Ultra-Fast-Lane-Detection 从环境搭建到复现完成(一)

UFAST车道线检测 Ultra-Fast-Lane-Detection 从环境搭建到复现完成(一)

m0_46364958的博客 4345

深入理解Android中的Handler机制

Handler机制在Android多线程编程中可以说是不可或缺的角色,也是必须掌握的内容,所以深入掌握并应用Handler异步处理机制在Android开发中显得特别重要。它在使用的过程中主要与Messgae、MessageQueue、和Looper这三者一起使用,实现Android的异步消息处理机制。

reakingf的博客 2万+

[ vulhub漏洞复现篇 ] Drupal XSS漏洞 (CVE-2019-6341)

[ vulhub漏洞复现篇 ] Drupal XSS漏洞 (CVE-2019-6341) Drupal是使用PHP语言编写的开源内容管理框架(CMF),它由内容管理系统(CMS)和PHP开发框架(Framework)共同构成,在GPL2.0及更新协议下发布。Drupal在某些情况下,通过文件模块或者子系统上传恶意文件触发XSS漏洞。

qq_51577576的博客 2208

Android——深入理解handler机制

handler原理解析,非常详细

海晨忆的博客 3010

Python 爬虫实战:爬取豆瓣读书评论并分析

摘要:本文以豆瓣读书《活着》评论数据为例,详细讲解Python爬虫开发与文本分析全流程。首先通过requests库爬取评论数据,解决分页、反爬等问题;然后利用BeautifulSoup解析页面提取评论内容、评分等核心信息;最后结合jieba进行关键词提取、snownlp完成情感分析,并通过可视化展示结果。分析显示该书评分以5星为主(占比70%),正面评论达82%,核心关键词为"活着""余华""生命"。全文包含完整代码与详细解析,帮助读者掌握非结构化

2503_91057718的博客 1497

Python爬虫实战:使用最新技术爬取新华网新闻数据

在当今信息爆炸的时代,网络爬虫技术已经成为获取互联网数据的重要手段。作为国内权威新闻媒体,新华网每天发布大量高质量的新闻内容,这些数据对于舆情分析、市场研究、自然语言处理等领域具有重要价值。本文将详细介绍如何使用Python最新技术构建一个高效、稳定的新华网新闻爬虫系统。本文详细介绍了如何使用Python最新技术栈构建一个高效、稳定的新华网新闻爬虫系统。我们从基础爬虫开始,逐步添加了代理支持、用户代理轮换、请求延迟、重试机制、动态页面渲染、数据存储等高级功能,最终实现了一个生产可用的分布式爬虫系统。

2201_76125261的博客 1771

Android线程间通信机制——深入理解 Looper、Handler、Message

Android中的Looper , Handler , Message有什么关系?本篇博客目的首先为大家从源码角度介绍3者关系,然后给出一个容易记忆的结论。 1、 概述 Handler 、 Looper 、Message 这三者都与Android异步消息处理线程相关的概念。那么什么叫异步消息处理线程呢? 异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取

zhangcanyan的博客 1698

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

深入理解android Handler机制

通过源码理解android 中Handler,Message,Looper,MessageQueue之间的关系,之前说到handler机制,都是在网上看到得别人是怎么讲解的,自己就机械的记下来,回来忘了再到网上搜一堆资料看看,对自己本身能力没有太大的提升。纸上得来终觉浅 绝知此事要躬行。开始试着自己阅读源码,进行深入理解一下。 首先分别介绍一些handler,message,Looper,Mess

宋大人专栏 558

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Android 深入理解Handler

&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;nbsp;Handler对于大家来说并不陌生,它对于android的消息机制来说至关重要。我们经常会通过Handler在子线程中更新UI,当然Handler不仅仅可以更新UI,还

养生阿华田 995

廖雪峰Python教程[完整版]

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

android handler 异步,深入理解Android中的Handler异步通信机制

一、问题:在Android启动后会在新进程里创建一个主线程,也叫UI线程(非线程安全)这个线程主要负责监听屏幕点击事件与界面绘制。当Application需要进行耗时操作如网络请求等,如直接在主线程进行容易发生ANR错误。所以会创建子线程来执行耗时任务,当子线程执行完毕需要通知UI线程并修改界面时,不可以直接在子线程修改UI,怎么办?解决方法:Message Queue机制可以实现子线程与UI线程...

weixin_33841242的博客 402

安卓开发21:深入理解Handler

Handler相关说明: 主要接受子线程发送的数据, 并用此数据配合主线程更新UI。 解释:安卓的UI线程(即OnCreate函数创建的线程)是线程非安全的。也就是说,在UI线程中,使用sleep这样的函数会导致整个线程延迟,但是我们在安卓开发中,往往会经常遇到一些延迟比较厉害的操作,(例如通过HTTP获取数据信息)如果放在主线程中,则会影响UI界面的渲染。但是如果另外新开一个线程,则由于UI

自娱自乐的代码人 3509

Android消息机制之Handler的深入理解

欢迎使用Markdown编辑器写博客上周老大让我主持了一个团队技术培训的会议,会议的内容是Handler技术的整体使用流程,包括从Java端到Native端的分析。借此机会,写成一篇文章记录一下成果。若有不足之处,希望大家可以指出,欢迎互相讨论,谢谢。Java层中的消息生成是从用户创建的Message对象而来的,它是一个由Runnable封装过的对象。或者从Message Pool调用getsMes

Sheldon Tse的技术博客 480
上一篇: 深入剖析Java中ThreadLocal原理
下一篇: 安卓触摸事件分发机制分析
_蓝橙
博客等级 码龄7年 1179粉丝 174原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值