Android 第十四课——Handler Looper Message

一、基础概念java

1)android.os.Handler android

2)主要接受子线程发送的数据, 并用此数据配合主线程更新UI. 缓存

3)应用程序一旦启动,Android UI 这个主线程的生命周期就开始了,然而,Android UI 线程并非线程安全的,也就是说,更新UI只能在主线程中同步更新,子线程中异步操做是危险的。因此,项目中若是咱们直接new Thread 内部去更改Android UI,每每会报错误以下:安全

    java.lang.RuntimeException: Can't create handler inside thread that has not called
异步

为了不错误发生,那么更新Android UI 必须在主线程中操做,具体如何操做呢?Handler就发挥了特的做用。Handler的使用同时也会带来许多相关的知识,下面一一讲解。ide


二、实例化oop

1)采用默认的方式 new Handler();项目中不多使用这种方式。若是他是主线程中运行的,那么这个handler对象内部绑定了一个Looper对象Looper.getMainLooper();Looper对象是用来干吗的呢? Looper类是用来为一个线程开启一个消息循环。能够这样获取对应的线程:handler.getLooper().getThread()。默认状况下Android中新诞生的线程是没有开启消息循环的(主线程中new的则有)。换句话说,Looper内部有一个线程对象,这个对象会轮询获取消息队列的消息,这个消息队列就是MessageQueue,Looper对象经过MessageQueue来存放消息和事件,一个线程只能有一个Looper,对应一个MessageQueue。post

总结就是:性能

    A:主线程中 handler = new Handler();那么这个handler内部绑定了 Looper.getMainLooper() 对象或Looper.myLooper();spa

    B:在子线程中,如在Thread中 handler = new Handler();那么这个handler的Looper对象时空的。

那么,关于子线程中应该如何为handler注册Looper呢?能够这样使用

  HandlerThread handlerThread = new HandlerThread("sub thread");

  handlerThread.start(); // 这句很重要 ,应该是为线程异步运行提供环境

  handler = new Handler(handlerThread.getLooper());

2)采用继承方式,继承方式就是多了Looper对象的绑定方法,这样绑定确实有点麻烦。

     class MyHandler extends Handler {
         public MyHandler() {
         }
 
         public MyHandler(Looper looper) {
             super(looper);
         }
 
         // 子类必须重写此方法,接受数据
         @Override
         public void handleMessage(Message msg) {
              // msg.what 进行判断,调用对应的方法更新UI
         }
     }

3)采用内部类方式,内部类方式与默认new Handler相差无几,惟一的区别就是内部类须要重写handleMessage方法,否者意义就不大了,项目中每每使用这种方式。那么为何推荐这种方式呢?首先咱们定义个全局的私有Handler,而后定义时采用内部类实例化对象,下次使用时直接调用handler,只要保证这个handler的Looper对象是主线程的Looper就好,也就是不要在本身的Thread中去实例化handler。


三、handler调用

1)因为一切关于消息队列的事情都有Looper对象处理,那么就没必要过于深究了。如今只要好好理解如何使用handler,关于handler同步的问题,若是handler内部绑定的是主线程的Looper对象,那么,在咱们调用 handler.post(new Thread())的时候,这个注册的Thread实际上是在主线中串行,而不是并行。就好像调用的是Thread对象的run方法而非start方法,那么意义就不大了!

2)项目中耗时的工做应该给一个异步的子线程处理,若是你放在主线程中的话,界面会出现假死现象,,若是5秒钟尚未完成的话,会收到Android系统的一个错误提示 "强制关闭"。然而子线程又不能更新主线程的UI,那么问题就来了,应该如何结合Handler让子线程与主线程并行呢?一种方式就是采用 handlerThread 为 当前的handler对象绑定一个全新的 Looper对象,那么就能够实现以上要求了。固然,更好的方式是:单独new Thread ,在Thread内部调用已经实例化话好的handler对象,这样也是一个异步调用。


4 handler消息传送

1)Message对象是与handler绑定的,handler能够采用sendMessage(Message)方式把Message对象发送到handler的handleMessage方法中,通常咱们采用message.what 方法做为不一样消息类型的标识;另外,message的两个参数 arg1 与 arg2 是效率相对较高的,由于他们消耗系统性能较少。

2)Bundle对象是handler的一个成员变量,能够把bundle当作是一个特殊的Map对象,两者都是用来缓存数据,只是Bundle的key只能是String,并且Bundle的方法相对Map更为丰富。另外,Bundle对象不局限与handler,在intent或者在Activity的onCreate方法中到处可见。


总结:

    不能在子线程中直接更新Android UI ,须要采用Handler处理,然而handler处理时须要注意内部的Looper对象是否已经绑定,若是没有绑定须要手动注册一个Looper。对于同步仍是异步调用,也须要适当的处理。

相关文章
相关标签/搜索