Handler学习

0. 跨线程的核心原理

线程A通过调用线程B的Handler, 将需要传递的信息或者数据插入到线程B的消息队列中,

然后线程B从消息队列中取出消息,进行处理。

实现了线程 A  ->  线程B 的通信。

1.Handler 面试题:

1.1 一个线程可以有多个Handler,

例如主线程中可以创建任意个handler


1.2 一个线程只有一个Looper.  

Looper 是一种隐式的实现, ActivityThread.main()  中创建了一个Looper, 并且调用 loop()方法。

    public static void main(String[] args) { // 由AMS启动初始化, Message: 进程内的管理,提供初始化
        ...
        Environment.initForCurrentUser(); // 题外话
        ...
        
        Looper.prepareMainLooper(); 
        ...
        Looper.loop(); // 不断循环读取消息,处理任务

Looper.prepareMainLooper() 中会调用 Looper.prepare()去创建Looper(唯一创建方式

保持在ThreadLocal即绑定Thread, 并且一个线程只能创建一个Looper,否则保错

public final class Looper {
    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));
    }


Looper源码分析:

TD: Thread / ThreadLocal/ ThreadLocalMap 
主线程 -》 <sThreadLocal, Looper>  线程和Looper 一一对应

1.3  Handler容易造成内存泄漏的原因和解决方法

原因:MessageQueue 持有 Message,  Message持有Handler -> Handler 持有this Activity -> Activity 持有大量变量,即大量内存
因此容易造成内存泄漏。 (JVM 垃圾回收机制:可达算法分析)
解决方法:
(1) 在destroy 里面清理Handler中的所有Message
(2)Activity 创建的Handler 声明为static , 用软引用或者弱引用持有activity

1.4 主线程可以创建Handler的原因 以及 在子线程中创建的方式

Looper在应用已启动的时候,即ActivityThread.main() 中,调用了Looper.prepareMainLooper -> loop() 初始化了。因此, 主线程可以直接创建Handler。

如果要在子线程new Handler, 需要关注多线程同步的问题。

-》 使用HandlerThread,  使用了一个内置锁(开锁和上锁是由JVM完成的): synchronized

public class HandlerThread extends Thread {
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
}

注意notifyAll(), 这里通知所有等待锁的地方(例如 HandlerThread.getLooper()) 

wait() 会释放锁,线程可以执行其它内容。

其中Looper.myLooper()

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

1.5 子线程维护的Looper,在消息队列没有消息时会退出;主线程则不会退出(AMS 中ActivityThread.main() 启动loop(), 且主要操作由子类Handler完成)


2. Handler工作流程:类似传送带

熟记该类比流程图加深理解

3.Handler主要方法



最终都是调用 MessageQueue.enqueueMessage的方法,进行插入到消息队列的队头(看源码清晰)

3.1 Handler 的关键点 (跟踪源码)


Looper.loop() 从消息队列里取出Message, 最终回调Handler.handleMessage

Android handler机制是一种在Android中用于处理异步消息和线程通信的重要机制。其主要作用是将消息和任务抛到主线程的消息队列中,以便主线程按照一定的规则按照队列中的顺序处理这些消息和任务。 1. Handler的实例化:在Android中,创建一个Handler的实例可以通过以下两种方式实现: 直接实例化: 创建一个Hanlder对象,代码示例: Handler handler = new Handler(); 绑定Looper:在子线程中创建Handler的话,需要先通过以下代码获取Looper对象,然后再将其传入Handler的构造函数中: Looper looper = Looper.myLooper(); Handler handler = new Handler(looper); 2. Handler的使用:当一个线程需要将一个耗时的任务交给主线程去执行的时候,它可以使用Handler来完成。以下是Handler的常见用法示例: 使用Handler处理消息: Handler myHandler = new Handler() { public void handleMessage(Message msg) { //在这里处理消息 } }; Message msg = myHandler.obtainMessage(); Bundle bundle = new Bundle(); bundle.putString("my_key", "my_string"); msg.setData(bundle); myHandler.sendMessage(msg); 使用Handler更新UI: Handler myHandler = new Handler() { public void handleMessage(Message msg) { //更新UI } }; myHandler.sendEmptyMessage(0); 3. Handler的原理:在Android系统中,所有的UI操作都必须在主线程上完成。这时,Handler就扮演了一个传递任务的中介角色。它把来自子线程的消息和任务封装成Message对象,最后以一定的顺序扔到主线程的消息队列中等待执行。主线程通过Looper不断地循环读取消息队列中的消息和任务,然后依次执行。这就是Handler机制的基本原理。 4. Handler配合其他机制使用:为了更好地发挥Handler的作用,还可与一些其他机制有效配合使用,例如:AsyncTask、MessageQueue等等。通过多种机制的相互配合,可以实现复杂的异步消息处理和并发控制,提升了Android应用程序的性能和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值