`

Android Handler和HandlerThread

 
阅读更多

        

        Handler的官方解释如下:

        A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.Each Handler instance is associated with a single thread and that thread's message queue.

        Handler会关联一个单独的线程和消息队列。Handler默认关联主线程,虽然要提供Runnable参数,但默认是直接调用Runnable的run()方法。也就是默认下会在主线程执行,如果在这里面的操作会有阻塞,界面也会卡住。如果要在其他线程执行,可以使用HandlerThread。

        Handler的使用方法:

        

Handler handler = new Handler(){

        @Override
        public void handleMessage(Message msg){

                 super.handleMessage(msg); 
                 //处理发送过来的消息
                 Bundle b = msg.getData();
                System.out.println("msg:" + msg.arg1);                              
                System.out.println("msg:" + b.getString("name") + " - age:" + b.getInt("age")); 
        }

};

        HandlerThread使用方法:
//把上面创建Handler的代码
  Handler handler = new Handler() {
      ...
  }   

 //改为:  
   HandlerThread thread = new HandlerThread("athread");     
   thread.start(); //要把线程启动   
   Handler handler = new Handler(thread.getLooper()) {
       ... 
    } 
 
 下面详细讲解下Handler的消息机制
 1.相关类:
 Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一队列,终由Handler处理。
 Handler:处理者,负责Message的发送和处理,使用Hander时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
 MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。
 当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
 Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
 Thread:线程,负责调度整个消息循环,即消息循环的执行场所。
 
 Handler,Looper和MessageQueue就是简单的三角关系。Looper和MessageQueue一一对应,创建一个Looper的同时,会创建一个MessageQueue。而Handler与他们的关系,只是简单的聚集关系,即Handler里会引用当前线程里的特定Looper和MessageQueue。
 这样说来,多个Handler都可以共享同一Looper和MessageQueue了。当然,这些Handler也就运行在同一个线程里。
 
 接下来,我们简单的看下消息的循环过程:

 生成
  Message msg = mHandler.obtainMessage();        
  msg.what = what;       
  msg.sendToTarget(); 
 
 发送
   MessageQueue queue = mQueue;          
   if (queue != null) {            
         msg.target = this;              
         sent = queue.enqueueMessage(msg, uptimeMillis);         
   } 
  在Handler.java的sendMessageAtTime(Message msg,long uptimeMillis)方法中,我们看到,它找到它所引用的MessageQueue,然后将Message的target设定成自己(目的是为了在处理消息环节,Message能找到正确的Handler),再将这个Message纳入到消息队列中。

 抽取
    Looper me = myLooper();          
    MessageQueue queue = me.mQueue;         
    while (true) {              
        Message msg = queue.next(); // might block             
        if (msg != null) {                  
            if (msg.target == null) {
               // No target is a magic identifier for the quit message.                               return;                
            }                  
            msg.target.dispatchMessage(msg);                 
            msg.recycle();             
          }         
     } 
  
 在Looper.java的loop()函数里,我们看到,这里有一个死循环,不断地从MessageQueue中获取下一个(next())Message,然后通过Message中携带的target信息,交由正确的Handler处理(dispatchMessage方法)。

 处理
      if (msg.callback != null) {             
          handleCallback(msg);         
       } else {              
           if (mCallback != null) {                  
                if (mCallback.handleMessage(msg)) {                    
                     return;                
                 }             
            }              
            handleMessage(msg);         
       } 
 
 在Handler.java的dispatchMessage(Message msg)方法里,其中的一个分支就是调用handleMessage方法来处理这条Message,而这也正是我们在职责处描述使用Handler时需要实现handleMessage(Message msg)的原因。
 至于dispatchMessage方法中的另外一个分支,将在后面的内容中说明。
 至此,我们看到,一个Message经由Handler的发送,MessageQueue的入队,Looper的抽取,又再一次地回到Handler的怀抱,而绕的这一圈,也正好帮助我们将同步操作变成了异步操作。
 
 下面,我们讨论下Handler所处的线程及更新UI的方式
 在主线程(UI线程)里,如果创建Handler时不传入Looper对象,那么将直接使用主线程(UI线程)的Looper对象(系统已经帮我们创建了);在其他线程里,如果创建Handler时不传入Looper对象,那么,这个Handler将不能接收处理消息。在这种情况下,通用的作法是:
 
        class LooperThread extends Thread {                                
              public Handler mHandler;                                
              public void run() {                                                 
                   Looper.prepare();                                       
                   mHandler = new Handler() {                                                             public void  handleMessage(Message msg) {                                                       // process incoming messages here                                                      }                                                                     };                                                 
                Looper.loop();                                
           }               
         }
 
 在创建Handler之前,为该线程准备好一个Looper(Looper.prepare),然后让这个Looper跑起来(Looper.loop),抽取Message,这样,Handler才能正常工作。
 因此,Handler处理消息总是在创建Handler的线程里运行。而消息处理中,不乏更新UI的操作,不正确的线程直接更新UI将引发异常。因此,需要时刻关心Handler在哪个线程里创建的。
 如何更新UI才能不出异常呢?SDK告诉我们,有以下4种方式可以从其他线程访问UI线程:
 1.Activity.runOnUiThread(Runnable)
 2.View.post(Runnable)
 3.View.postDelayed(Runnable,long)
 4.Handler
 其中,对于View.post(Runnable)方法。在post(Runnable action)方法里,View获取得到当前线程(即UI线程)的Handler,然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。在Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。而此时,已经路由到UI线程里,因此,我们可以毫无顾虑的更新UI。

 因此,注意如下几点:
 1.Handler的处理过程运行在创建Handler的线程里
 2.一个Looper对应一个MessageQueue
 3.一个线程对应一个Looper
 4.一个Looper可以对应多个Handler
 5.不确定当前线程时,更新UI时尽量调用post方法

    

 

         Android提供的HandlerThread继承自Thread,并且在这个线程里放入了一个Looper(android.os.Looper -> java.lang.Object)对象,也就是说这个Looper对象是在新建线程里运转的。Looper对象可以简单的理解成一个循环处理工具。为了更好的理解HandlerThread,应该先看一下Handler相关的内容。

          从Android文档的Handler(android.os.Handler -> java.lang.Object)描述可以看出,Android的Handler和Java的Handler(java.util.logging.Handler -> java.lang.Object)是基本上没有关系的。Android提供的Handler是为了传递消息(android.os.Message)和启动Runnable对象而使用的。

android.os.Handler对象只能在某一个线程中运行并可以使用这个线程的消息队列(Message queue)。从官方API文档可以看到,实例化Handler有4种方法。其中有2种是需要Looper对象参数的,这2种构造方法就可以使Handler运行在包含给定Looper对象的线程中;如果不给定,则运行在当前线程中(一般没有新建线程的情况下,会运行在Android程序主线程中,也就UI线程中)。

          android.os.Handler在多线程和IPC(进程间交互)中都起到非常重要的做用。

 

android.os.Handler可以通过Looper对象实例化,并运行于另外的线程中,Android提供了让Handler运行于其它线程的线程实现,也是就HandlerThread。HandlerThread对象start后可以获得其Looper对象,并且使用这个Looper对象实例Handler,这样Handler就是工作于前面实例的HandlerThread(其实质就是线程Thread)里了。HandlerThread使用常用代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void useHanlerThread() {
 
    // two ways to construct HandlerThread
    HandlerThread hThread = new HandlerThread("AnyName",
 
            // a property in android.os.Process
            Process.THREAD_PRIORITY_BACKGROUND);
 
    // HandlerThread hThread2 = new HandlerThread("AnyName");
    hThread.start();
 
    // get Looper object of hThread(HandlerThread)
    Looper looper = hThread.getLooper();
 
    Handler h = new Handler(looper) {
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
        }
    };
 
}

HandlerThread是继承于Thread的,所以在Thread的适用范围内HandlerThread是同样适用的。如果在android.os.Handler里需要执行一些非常耗时的任务,就应该把Handler放到HandlerThread里面执行(或者在Handler里新开线程执行),而不应该直接在UI线程中执行,否则会增加出现ANR(Application Not Responding)的可能。

分享到:
评论

相关推荐

    Looper、Handler与HandlerThread

    在Android开发中,Looper、Handler和HandlerThread是三个非常重要的组件,它们构成了Android消息处理机制的基础,用于在主线程中处理来自其他线程的消息。理解并熟练运用这三个组件,对于编写高效、响应迅速的...

    了解Android核心:Looper,Handler和HandlerThread

    在Android开发中,理解核心组件如Looper、Handler和HandlerThread对于构建高效且响应式的用户界面至关重要。这些组件共同协作,确保UI线程不被阻塞,从而提供流畅的用户体验。 首先,主线程(也称为UI线程)是...

    Thread、Handler和HandlerThread关系详解

    ,这个题目有点意思,对于很多人来说,可能对Thread和Handler很熟悉,主要涉及到Android的消息机制(Handler、Message、Looper、MessageQueue),详见《 从Handler.post(Runnable r)再一次梳理Android的消息机制(以及...

    Android HandlerThread 全面解析

    `HandlerThread`是Android中的一个内置类,它继承自`Thread`,并添加了`Looper`和`Handler`的支持。通常,当我们需要创建一个新的工作线程来处理耗时任务时,需要手动初始化`Looper`和`Handler`,而`HandlerThread`...

    HandlerThread

    由于HandlerThread保持着对Looper和关联Handler的引用,如果Handler引用了Activity或Context,可能导致Activity无法正常销毁。因此,最好在Activity的`onPause()`或`onDestroy()`方法中移除Handler的引用。 8. **...

    android-Handler的使用

    为了解决这个问题,Android 引入了 Handler 和 Looper 的概念。Handler 可以在子线程中创建,但它的实例通常与主线程关联,因为它需要在主线程中执行任务,以便安全地更新 UI。子线程通过调用 `sendMessage()` 或 `...

    android HandlerThread 实例

    在Android开发中,`HandlerThread` 是一个非常重要的组件,特别是在处理异步任务和线程通信方面。`HandlerThread` 是一个内置了Looper的线程,它可以为长时间运行的任务提供一个独立的消息处理循环,避免阻塞主线程...

    Android handler message奇怪用法详解

    Handler是Android中的一个类,它用于在不同的线程之间发送和处理消息。通常,我们使用Handler配合Looper和Message来实现在主线程(UI线程)中执行后台任务的结果。Looper是消息队列的循环器,它不断检查消息队列并...

    android 中Handler 的几种写法

    在Android开发中,`Handler`是一个至关重要的组件,它用于在主线程中处理来自其他线程的消息,确保UI更新和事件处理的同步性。本文将详细介绍`Handler`的几种常见写法,以及如何使用`Handler.Callback`进行消息处理...

    Android:Handler学习实例2(HandlerThread、Bundle传递参数)

    HandlerThread handlerThread = new HandlerThread("handler_thread"); //在使用HandlerThread的getLooper()方法之前,必须先调用该类的start()方法,否则获得的值为空值; handlerThread.start(); //创建...

    android多线程handler/message机制详解

    在 Android 中,多线程机制是基于 Handler 和 Message 机制的。 Handler 是什么?Handler 是一个处理器,它负责处理和绑定到该 Handler 的线程中的 Message。每一个 Handler 都必须关联一个 Looper,并且两者是一一...

    HandlerThread的使用与自定义HandlerThread

    在Android开发中,`HandlerThread` 是一个非常重要的组件,尤其在处理异步任务和线程间通信时。本文将深入探讨 `HandlerThread` 的使用、工作原理,并讲解如何自定义 `HandlerThread`,以及为什么在某些场景下我们...

    android handler和线程的简单实例

    在Android开发中,`Handler`、`Message`和线程是三个非常重要的概念,它们用于在应用程序的不同组件之间实现异步通信和数据传递。本文将深入讲解这些概念,并通过一个简单的实例来帮助初学者理解其工作原理。 首先...

    【Android开发入门】Android线程之Handler

    本知识点将深入探讨Android中的Handler机制,它是Android异步处理和消息传递的核心工具,帮助开发者解决多线程环境下UI更新的问题。 一、Android线程基础 Android系统主要分为两个线程:主线程(UI线程)和工作线程...

    android HandlerThread 使用demo

    在Android开发中,`HandlerThread` 是一个非常重要的线程管理工具,它结合了线程和消息处理机制,常用于创建后台线程处理耗时任务,以避免阻塞主线程,提升用户体验。本示例("android HandlerThread 使用demo")将...

    HandlerThread,AsyncTask,Handler的一个小例子

    总的来说,HandlerThread、AsyncTask和Handler都是Android中用于异步处理和UI更新的重要工具。理解并熟练掌握它们的使用,能帮助开发者编写出更加流畅、高效的Android应用。在实际项目中,应根据任务的性质和需求...

    Android开发工程师面试题之handler详解。android程序员,android开发面试资料,详解

    - `HandlerThread`是Android提供的一种特殊线程,内部集成了Looper和Handler。 - 可以通过创建`HandlerThread`实例并启动线程,然后在该线程中使用Handler进行线程间的通信。 2. **Handler与AsyncTask的对比**: ...

    Android:Handler的post()方法和Thread的start()方法执行Thread的run()方法的区别

    import android.os.Handler; import android.app.Activity; import android.view.Menu; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { ...

    Android HandlerThread使用方法详解

    首先Handler和HandlerThread的主要区别是:Handler与Activity在同一个线程中,HandlerThread与Activity不在同一个线程,而是别外新的线程中(Handler中不能做耗时的操作)。 用法: import android.app.Activity; ...

Global site tag (gtag.js) - Google Analytics