一张图让你明白Handler、Message、Looper消息机制

转载请注明出自flowsky37的博客,尊重他人辛苦劳动!在android开发中,Handler太熟悉了,处处可见。确实挺好用的。它可以轻松的将任务切换到Handler所在的线程中去执行。如下面代码://发送messageMyHandler myHandler = new MyHandler(this); //业务逻辑 ... Message mess
摘要由CSDN通过智能技术生成

转载请注明出自flowsky37的博客,尊重他人辛苦劳动!

在android开发中,Handler太熟悉了,处处可见。确实挺好用的。它可以轻松的将任务切换到Handler所在的线程中去执行。如下面代码:

//发送message
MyHandler myHandler = new MyHandler(this);

        //业务逻辑
        ...
        Message message = new Message();
        message.what = 0x001;
        myHandler.sendMessage(message);
//接收message
public class MyHandler extends Handler {
   

    private Context context;

    public MyHandler(Context context) {
        this.context = context;
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what){
            case 0x001:

                //业务逻辑
                //...

                Toast.makeText(context,"收到messge",Toast.LENGTH_SHORT).show();
                break;
            default:
                super.handleMessage(msg);
                break;
        }
    }
}

so easy,对吧!很多人认为Handler的作用是更新UI,这没问题。但是更新UI只是Handler的一个特殊使用场景。具体来讲,所有比较耗时的操作一般都是在子线程中完成,否则容易引起ANR,如读写文件、数据插入、网络请求等,完成后需要对UI进行修改的,但是由于android开发规范限制,子线程不能更新UI。所以这时候通过Handler将更新UI的操作切换到主线程中执行。通俗的讲,Handler不是为了UI而生,只是常被大家用来更新UI。Handler的主要作用应该是将一个任务切换到某个指定的线程中去执行。

Android的消息机制主要是指Handler运行机制,关于Handler运行机制,我们不得不提到其底层的MessageQueue与Looper。其关系大概如下图:
Handler、MessageQueue、Looper关系图

没看懂?没关系,后面会更详细的。先说一下MessageQueue与Looper是啥呢!

MessageQueue:消息队列,它内部存储了一组消息,以队列的形式对外提供插入和删除的工作。内部结构不是真正的队列,而是采用单链表的数据结构来存储消息列表。

Looper:可以理解为消息循环。MessageQueue 只是一个消息的存储单元,它不能去处理消息,Looper 填补了这个功能,Looper 会以无限循环的模式去查看Message中是否有新消息,否则就一直等待。

重点:如果需要使用Handler就必须为当前线程创建一个Looper,因为线程默认是没有Looper的。如果线程中没有Looper的话,会抛出异常的。我我们可以一起看看一下Handler的构造源码,它有好几个构造函数:


    /**
     * Default constructor associates this handler with the {@link Looper} for the
     * current thread.
     *
     * If this thread does not have a looper, this handler won't be able to receive messages
     * so an exception is thrown.
     */
    public Handler() {
        this(null, false);
    }

无参数的,接着往下看:

/**
     * Constructor associates this handler with the {@link Looper} for the
     * current thread and takes a callback interface in which you can handle messages.
     * If this thread does not have a looper, this handler won't be able to receive messages
     * so an exception is thrown.
     */
    public Handler(Callback callback) {
        this(callback, false);
    }

还有好几个其它的构造方法,可自行阅读源码。这两个构造方法都指向了this(callback, false),我们接着看this(callback, false)的具体实现:


    public Handler(Callback callback, boolean async) {

         ...

        //获取当前线程的looper对象 
        mLooper = Looper.myLooper();
        //判断Looper是否为null
        if (mLooper == null) {
        //如果为null则报异常
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

通过源码可以看出,在创建Handler实例的时候,先会通过Looper.myLooper()去获取当前线程的Looper,然后判断looper是否为null。如果为null,会提示通过Looper.prepare()去创建。
我们接着看下Looper.prepare()的源码:

 /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    public static void prepare() {
        prepare(true);
    }

prepare()是一个空构造函数,其内部是调用了prepare(true),我们接着看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));
    }

最后一行代码很很清楚的显示了创建了一个Loope

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值