Android学习之Handler

Handler机制工作原理

定义

是Android的一套消息传递机制

将工作线程中需更新UI的操作信息 传递到 UI主线程从而实现 工作线程对UI的更新处理,最终实现异步消息处理

ABOUT

主线程处理与UI有关的操作
子线程处理一些耗时的操作(人为手动开启)
Message是线程之前通讯的数据单元,存储需要传递的消息
Handler添加Message到Message Queue;处理Looper的Message。是线程消息的主要处理者。
Looper消息循环的核心
Message Queue是一种数据结构,存储Message

UI操作是线程安全的,仅允许UI线程(主线程)操作UI,为了满足:多个线程可并发操作UI以及保证线程安全,使用Handler通知主线程更新UI。

流程

  1. 异步通信准备

    在主线程创建Looper,Message Queue(可以理解为从属于Looper),以及Handler对象

  2. 消息发送

    Handler将Message发送到Message Queue

  3. 消息循环

    Looper取出Message Queue中的消息

    Looper将取出的Message发给处理者Handler

  4. 消息处理

    Handler接收并处理Message,并进行UI操作

在这里插入图片描述

  • 1个线程(Thread)只能绑定 1个循环器(Looper),但可以有多个处理者(Handler)
  • 1个循环器(Looper) 可绑定多个处理者(Handler)
  • 1个处理者(Handler) 只能绑定1个1个循环器(Looper)

一. 创建Looper对象

  1. 主线程创建的时候自动创建Looper,无需手动创建

  2. Looper的构造方法私有,仅在prepare()中使用,如果threadLocal能获取到值意味着已经创建过,会抛出异常,保证了一个线程仅能拥有一个Looper。

  3. prepare()方法的参数中有一个boolean,表示是否可以退出循环,主线程不可以,子线程可以。

  4. Looper的构造方法

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

创建Looper对象时,同时也绑定了一个Message Queue以及当前线程。

二. Looper开始工作

调用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;
    。。。
    for (;;) {
        Message msg = queue.next(); // might block
        。。。
    }
}
  • 首先获取绑定的Message Queue

  • for(;;)开启死循环

  • queue.next()获取Message

  • 处理消息

循环虽然是死循环,但有方法可以退出:

quit():立即退出

quitSafely():先打标记安全退出,即处理完Message之后,再推出

三.Message Queue读取数据

  1. nextPollTimeoutMillis是很重要的参数,正常循环时,此参数为0。当有延迟消息,消息没准备好时,则会设置一个延迟时间,当Message为空,则设置为-1

  2. nextPollTimeoutMillis为-1时,消息队列陷入阻塞状态

  3. 为了保证线程安全,在这个线程中要锁住Message Queue对象

使用

Handler.sendMessage()

以下代码采用自定义一个Handler类继承自Handler,也可以选择匿名内部类

//新建一个自定义Handler对象
MyHandler handler=new MyHandler();
//新开工作线程,handler将消息发送,并开启线程
new Thread(new Runnable() {
        @Override
        public void run() {
            Message msg=Message.obtain();
            msg.what=1;
            msg.obj="nihao";
            handler.sendMessage(msg);
        }
    }).start();

//自定义一个Handler,并在handlerMessage方法中完成主线程的UI操作
private class MyHandler extends Handler{
    @Override
    public void handleMessage(@NonNull Message msg) {
        super.handleMessage(msg);
        if (msg.what==1){
            
        }
    }
}

Handler.post()

此种方式是在新线程使用handler提交UI操作

final Handler handler=new Handler();
new Thread(new Runnable() {
    @Override
    public void run() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                binding.tv.setText("niniin");
            }
        });
    }
}).start();

以上两种方式都是在主线程使用Handler的,在子线程,Looper不会自动创建,需要手动创建并且loop

代码展示:(以post的方式)

new Thread(new Runnable() {
    @Override
    public void run() {
        Looper.prepare();
        Handler handler1=new Handler();
        handler1.post(new Runnable() {
            @Override
            public void run() {
                //
            }
        });
        Looper.loop();
    }
}).start();

总结

post方法和handleMessage方法的不同在于,post的runnable会直接在callback中调用run方法执行,而sendMessage方法要用户主动重写mCallback或者handleMessage方法来处理。

其他

Looper的死循环

Looper不会一直消耗系统资源,当Looper的MessageQueue中没有消息时,或者定时消息没到执行时间时,当前持有Looper的线程就会进入阻塞状态。

当有消息入队时则会唤醒线程(重点:消息入队按照delay时间,时间短先入队,时间长后入队,时间相同则看入队时间先后

Handler是如何引起内存泄漏的以及解决

当Handler是非静态内部类或匿名Handler内部类时,会持有外部应用,在Activity销毁时,由于Handler可能有未执行完/正在执行的Message。导致Handler持有Activity的引用。进而导致GC无法回收Activity

Handler的生命周期 > 外部类的生命周期

以上都会导致内存泄漏

解决:

Activity销毁时,清空Handler中,未执行或正在执行的Callback以及Message。

静态内部类+弱引用

Handler 是如何能够线程切换的

其实并没有线程切换,线程的切换执行关键也不在于Handler所在的线程而是在于Looper是在哪一个线程创建的。

Handler的生命周期 > 外部类的生命周期

以上都会导致内存泄漏

解决:

Activity销毁时,清空Handler中,未执行或正在执行的Callback以及Message。

静态内部类+弱引用

Handler 是如何能够线程切换的

其实并没有线程切换,线程的切换执行关键也不在于Handler所在的线程而是在于Looper是在哪一个线程创建的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值