Handler 机制学习

参考
Handler的理解、用法以及运行机制原理
android Handler机制原理 4个组成部分源码解析
Android Handler消息机制原理最全解读(持续补充中)

Handler是android提供用于更新UI的一套机制,也是消息处理机制。
Handler的主要作用有两个:
(1).在新启动的线程中发送消息
(2).在主线程中获取,处理消息。
当需要进行子线程和主线程(UI线程)通讯时,我们经常要用到Handler。
最常见的场景就是,UI在主线程初始化后,子线程做了一些耗时的数据操作,做完操作后要通知主线程拿到数据去更新UI。

Handler机制

在这里插入图片描述
 Handler机制也可叫异步消息机制,它主要由4个部分组成:Message,Handler,MessageQueue,Looper,在上面图中我们已经有了大致印象,接下来介绍一下这4个成员:

1.Message
  Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。使用Message的arg1和arg2便可携带int数据,使用obj便可携带Object类型数据。

2.Handler
  Handler顾名思义就是处理者的意思,它只要用于在子线程发送消息对象Message,在UI线程处理消息对象Message,在子线程调用sendMessage方法发送消息对象Message,而发送的消息经过一系列地辗转之后最终会被传递到Handler的handleMessage方法中,最终在handleMessage方法中消息对象Message被处理。

3.MessageQueue
  MessageQueue就是消息队列的意思,它只要用于存放所有通过Handler发送过来的消息。这部分消息会一直存放于消息队列当中,等待被处理。每个线程中只会有一个MessageQueue对象,请牢记这句话。其实从字面上就可以看出,MessageQueue底层数据结构是队列,而且这个队列只存放Message对象。

4.Looper
  Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当MesssageQueue中存在一条消息,Looper就会将这条消息取出,并将它传递到Handler的handleMessage()方法中。每个线程只有一个Looper对象。

了解了上述Handler机制的4个成员后,整个handler异步消息机制流程思路再理一遍:
  
  1.首先在UI线程我们创建了一个Handler实例对象,无论是匿名内部类还是自定义类生成的Handler实例对象,我们都需要对handleMessage方法进行重写,在handleMessage方法中我们可以通过参数msg来写接受消息过后UI线程的逻辑处理。
  
  2.接着我们创建子线程,在子线程中需要更新UI的时候,新建一个Message对象,并且将消息的数据记录在这个消息对象Message的内部,比如arg1,arg2,obj等,然后通过前面的Handler实例对象调用sendMessge方法把这个Message实例对象发送出去。
  
  3.之后这个消息会被存放于MessageQueue中等待被处理,此时MessageQueue的管家Looper正在不停的把MessageQueue存在的消息取出来,通过回调dispatchMessage方法将消息传递给Handler的handleMessage方法。
  
  4.最后前面提到的消息会被Looper从MessageQueue中取出来传递给handleMessage方法,消息得到处理。

handler 的 post 方法有啥用?

1. 先看用法1之主线程中使用:

new Handler().post(new Runnable() {
        @Override
        public void run() {
              mTextView.setText("post"); //更新UI
        }
    });

可以看到,new了Runnable像是开启了一个子线程,但是不然,大家可以看到这儿调用的是run方法,而不是start方法,因此并不是子线程,其实还是在主线程中(关于run和start的概念不清楚的可参考:https://www.jianshu.com/p/6b11e57cdc17),那为什么又要使用post方法呢?其实一般不这样用,也没人这样用,并没有多大意义,这就像是在主线程中给主线程sendmessage,并没有什么意义(我们知道sendmessage是子线程为了通知主线程更新UI的),主线程是可以直接更新UI的。

2 再看用法2之子线程中使用:

new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            mTextView.setText("post");//更新UI
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

由上面总结我们知道这儿的post并不是新开启的子线程,存在的子线程只有一个,即为new的Thread,那么为什么我们在其中可以settext做更新UI的操作呢? 其实post方法post过去的是一段代码,相当于将这个Runable体放入消息队列中,那么looper拿取的即为这段代码去交给handler来处理,其实也相当于我们常用的下面这段代码:

private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    mTextView.setText("handleMessage");//更新UI
                    break;
            }
        }
    };

看起来熟悉吧,就是用这个Runnable体代替了上面这一大段代码,当然,我们的post方法就可以执行UI操作了。

平常情况下我们一个activity有好多个子线程,那么我们都会采用上面这种handleMessage(msg)方式,然后case 0:case 1:等等,但是当我们只有一个子线程时呢,用post反而比上面一大串代码轻便了不少,何乐而不为呢?

总结

1.post使用场景:当有多个子线程要通知UI更新时,还是采用handler.sendMessage发消息方便,如果只有一个子线程更新UI时则直接通过post来传递Runnable,相当于也是发一条消息。

2.handle的 post 其实并没有新创建线程。

关于new Handler()与new Handler(Looper.getMainLooper())区别

如果你不带参数的实例化:Handler handler=new Handler(); 那么这个会默认用当前线程的Looper对象。

一般而言,如果你的Handler是要用来刷新UI的,那么就需要在主线程下运行。

情况:

1 要刷新UI,handler要用到主线程的Looper对象。

那么在主线程Handler handler=new Handler() 如果在其他非主线程也要满足这个功能的话,要Handler handler=new Handler(Looper.getMainLooper());

2 不用刷新UI ,只是处理消息。

当前消息如果是主线程的话,Handler handler=new Handler ;不是主线程的话,Looper.prepare() Handler handler=new Handler();Looper.loop() 或者Handler handler=new Handle(Looper.getMainLooper());

若是实例化的时候调用Looper.getMainLooper()就表示放到主线程中去处理。

若有不是的话,因为只有UI 线程默认Loop.prepare() Loop.loop()过,其他线程需要手动调用这两个。否则会报错。

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、付费专栏及课程。

余额充值