Android中的消息机制

Android中的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑。MessageQueue的中文翻译是消息队列,顾名思义,它的内部存储了一组消息,以队列的形式对外提供插入和删除的工作。注意MessageQueue底层其实采用单链表而不是队列;Looper的中文翻译为循环,在这里可以理解为消息循环。由于MessageQueue只是一个消息的存储单元,它并不能去处理消息,而Looper就填补了这个功能,Looper会以无限循环的形式去查找是否有新消息,如果有的话就处理消息,否则就一直等着。

Handler在创建的时候就会采用当前线程的Looper来构造消息循环系统,通过ThreadLocal获取到每个线程Looper。另外线程默认线程是没有Looper的,如果需要使用Handler就必须为线程创建Looper,而我们平时使用Handler有没有创建Looper,因为在UI线程,也就是ActivityThread,ActivityThread在创建的时候就会初始化Looper,这也是在主线程中可以使用Handler的原因。

Handler的主要作用是将一个任务切换到某个制定的线程中去执行,那么Android为什么要提供这个功能呢,这是因为Android规定访问UI只能在UI线程中进行,如果在子线程中访问UI,那么程序就会抛出异常,在ViewRootImpl这个隐藏类中,在android.view包下,在这个类中,有一个方法checkThread方法,如下:

    void checkThread() {
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }
    }

这个异常刚开始经常遇到,就是因为在子线程更新UI,就会抛出这个异常。但是又不建议在UI线程进行耗时操作因为会造成程序ANR,所以就Handler机制切换线程更新消息。

那么系统为什么不允许在子线程中访问UI呢?这是因为Android的UI空间不是线程安全,并发访问可能会造成不可预期的状态,那么为什么不加锁呢?首先加上所机制会让UI访问的逻辑变得负责,其次锁机制会降低UI访问的速度,会有等待的线程,就会阻塞一些线程,所以采用了Handler机制。
Handler的使用方法很简单,如果在UI线程创建Handler不需要初始化Looper,原因前面说过,如果在子线程中初始化Handler,需要初始胡Looper,代码如下:

	class MyThread extends Thread {
	      public Handler mHandler;

	      public void run() {
	          Looper.prepare();

	          mHandler = new Handler() {
	              public void handleMessage(Message msg) {
	                  // 处理收到的消息
	              }
	          };

	          Looper.loop();
	      }
	  }
需要在非UI线程中初始化Looper,先调用Looper.prepare();然后创建Handler。创建完Handler之后,调用Looper.loop进入循环状态。否则就会抛出如下异常

E/AndroidRuntime(27568):can't create handler inside thread that has not called Looper.prepare()

Handler创建完毕后,这个时候其内部的Looper以及MessageQueue就可以和Handler一起协同工作了,先给出一张工作流程图:


如图所示,创建Handler的线程一般为UI线程,如果不是UI线程,需要初始化Looper,这里假设为UI线程,Handler创建完毕之后,就可以和内部的Looper和MessageQueue一起协同工作了,然后通过Handler的post方法或者send方法发送一个消息,这个发送的过程是在其它线程,比如途中的Thread1,Thread2,Thread3,其中post方法最终也会调用send方法,我们表面调用的是sendMesage方法,最终会调用send方法,send方法被调用时,它会调用MessageQueue的enqueueMessage方法将这个消息放入到消息队列中,然后Looper发现有消息到来时,就会处理这个消息,最终Handler中的handlerMessage方法就会被调用,注意Looper,MessageQueue都是运行在创建Handler的线程中的,这样一来,Thread1,Thread2,Thread3中的业务逻辑就切换到创建Handler的线程中去执行了。










  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值