Handler机制及四个组成部分

本文介绍了Android中Handler消息传递机制,用于打破主线程依赖,实现在后台线程执行耗时操作并更新UI。详细讲解了Handler的线程模型、常用方法、四个组成部分,包括Message、Handler、MessageQueue和Looper。通过示例展示了如何在不同线程间切换,并讨论了取消任务、IdleHandler接口的使用,以及如何避免内存泄漏问题。
摘要由CSDN通过智能技术生成

    转载请注明出处:https://blog.csdn.net/github_38372075/article/details/80534808
    我的简书传送门

     今天我们来了解一下Handler。Android中操作UI控件需要在主线程中进行,为了打破对主线程的依赖(将耗时操作在后台线程执行,而将执行结果在ui线程中操作ui显示),Android引入了Handler消息传递机制。

Handler

     Handler有这样三个特点:
a.允许你去发送并处理一条与Runnable对象和MessageQueue相关联的消息。
b.每一个Handler实例都与一个单独的线程和该线程的MessageQueue相关。
c.当你创建一个新的处理程序时,它将绑定到正在创建的线程的线程/消息队列——从那个点开始,它将向该消息队列传递消息和runnables,并在它们从消息队列中释放时执行它们。
     实际上,根据我的理解,handler就是我们在各线程间处理发送消息数据的一种机制,实现线程间切换的一种方式。
     Handler有两个主要用途:
(1)将消息和runnables作为将来的某个点执行
(2)在不同的线程上执行要执行的操作

Handler线程模型

     先介绍了一下Handler的基本概念,下面就来说一下handler线程模型与一些handler常用的函数以及相关的类。
* 我们都知道,android的UI操作必须要在主线程中进行,为什么? 因为在多线程中同时执行UI操作是不安全的
* 可以把全部的操作都放在主线程中么? 不可以,耗时操作需要在后台线程执行,避免ANR
Handler线程模型.png
     也就是说,如果我们进行了耗时操作,如网络加载图片后,又想显示在我们的ImageView上,那么就需要进行线程间切换,使用handler将后台线程切换到主线程上后,进行UI操作。

Handler常用方法

构造方法

     Handler是Android中实现线程间切换机制的类
* public Handler() 无参构造,直接new。

    // 若只是执行runnable则不需要覆写handleMessage方法。因为执行runnable会自动忽略handleMessage方法本身。
    Handler handler0 = new Handler();
    // 如果我们要对发送的消息进行操作则需要覆写handleMessage方法。
    Handler handler1 = new Handler(){
         @Override
            public void handleMessage(Message msg) {
                // 获得消息后操作
            }
    }
  • public Handler(Callback callback)
  • public Handler(Looper looper)
  • public Handler(Looper looper,Callback callback) 参数1,looper;参数2,callback回调函数,相当于实现handler抽象方法handleMessage(Message msg);。
    public interface Callback {
        public boolean handleMessage(Message msg);
    }
调用函数
  • post(Runnable r) 将Runnable添加到MessageQueue中。此处要强调一点,如果发送的是runnable则会忽略掉handleMessage方法的执行,即使是发送含有runnable的Message则也会忽略掉handleMessage方法的执行
    public interface Callback {
        public boolean handleMessage(Message msg);
    }
  • postAtTime(Runnable r, long updateMillis) 在指定的时间点运行runnable。
  • postDelayed(Runnable r, long delayMillis) 在延迟一段时间后运行runnable。
    // 此处两个方法执行runnable时机一致
    handler.postDelayed(runnable,2000);
    handler.postAtTime(runnable,System.currentTimeMillis() + 2000);
  • postAtFrontQueue(Runnable r) 将Runnable放在队列最前端执行
  • sendEmptyMessage(int what) 发送一个空消息,参数为int型what(消息执行标识)。
  • sendMessage(Message msg) 发送消息。
  • sendMessageAtTime(Message msg,long updateMillis) 在指定时间点发送消息。
  • sendMessageDelayed(Message, long delayMillis) 在延迟一段时间后发送消息。
  • sendMessageAtFrontOfQueue(Message msg) 将message放在消息队列的最前面发送。
    sendMessage方法与post方法最后执行handleMessage方法或执行runnable的线程就是Handler的创建线程。
取消任务
  • removeCallbacks(Runnable r) 移除当前消息队列中runnable == r的消息。
  • removeCallbacks(Runnable r ,Object token) 移除当前消息队列中target == handler,runnable == r,Object == token 的消息。
  • removeMessages(int what) 取消所有标识为what的消息。
  • removeMessages(int what ,Object token) 取消含有token对象的被what标识的消息。
  • removeCallbacksAndMessages(Object token) 取消含有token的全部消息。

有关Handler常用类,四个组成部分

  1. Message:消息,被传递和处理的数据。其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
         Message作为传递的消息与Handler密不可分,所以此处我们稍微展开讲解一下Message属性与获得方式:
         Message的属性):
    • public int what 传递的消息执行标识,用于标记不同的消息。
    • public int arg1 类似与bundle来进行携带int类型的数据。
    • public int arg2 如果一个arg1还不够用再来个arg2。
    • public Object object 任意对象传递容器。类似于bundle,用于跨进程专递对象
    • Runnable callback 执行的runnable对象。
    • long when 发送的时机。
    • Handler target 所依附的handler,可以理解为通过这个target,这个消息会找到它该去的地方,然后执行对消息的操作也就是handleMessage方法。
           Message的获得(通常使用Message.obtain()或Handler.obtainMessage()方法来从消息池中获得空消息对象,以节省资源):
    • Message msg0 = new Message();
    • Message msg1 = Message.obtain();
    • public static Message obtain(Handler h)
    • public static Message obtain(Handler h, int what)
    • public static Message obtain(Handler h, int what, Object obj)
    • public static Message obtain(Handler h, int what, int arg1, int arg2)
    • public static Message obtain(Handler h, int what, int arg1, int arg2, Object obj) 参数1:targetHandler,参数2:what标识符,参数3:int型数据,参数4:int型数据,参数5:Object对象。
    • public static Message obtain(Message orig) 相当于拷贝某个Message而获得Message。
    • public static Message obtain(Handler h,Runnable callback) 传入targetHandler与需要回调执行的runnable。
  2. Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。Handler类的主要作用:(有两个主要作用)
    a. 在工作线程中发送消息;
    b. 在主线程中获取、并处理消息。
  3. MessageQueue:消息队列,本质是一个数据结构,用来存放Handler发送过来的消息,并按照FIFO规则(先进先出)执行。当然,存放Message并非实际意义的保存,而是将Message串联起来,等待Looper的抽取。
  4. Looper:消息泵或循环器,不断从MessageQueue中抽取Message。因此,一个MessageQueue需要一个Looper。
  5. Thread:线程,负责调度整个消息循环,即消息循环的执行场所。
    Handler简易关系.png
         此处我们画一个简易图来逐步了解Handler的运行机制。图中Handler(左右两个handler为同一个handler)可以与MessageQueue以及Looper在同线程中,也可在不同线程中。

Handler进程间切换举例

     到这里,我想我们脑中有了一个对Handler大致的理解,渐渐的看清了它的样子,那么接下来,我们来写一些代码,来看看handler究竟是怎样运行,工作的。

主线程创建handler

     为了节约版面,我们不列举每一种方法,只举例有代表性的方法,其他的都会提交到我的github中Handler传送门,大家有需要可以去下载研究。
* 我们先在主线程中创建handler而在非主线程中来调用post(Runnable r),观察是否最后runnable运行的线程为主线程(代码段中post(View v)方法为button点击调用函数)。

public void post(View v) {
        Log.e("tag", " ------>>> " + "点击Post按钮 " + getThreadName());
        // 在主线程创建handler
        final Handler handler = new Handler();
        // 创建一个非主线程的新线程
        Thread thread = new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        Log.e("tag", " ------>>> " + "执行非主
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值