Android Handler、Loop 的简单使用 和 HandlerThread 总结使用

1、子线程和子线程之间的通信

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package  lib.com.myapplication;
import  android.os.Bundle;
import  android.os.Handler;
import  android.os.Looper;
import  android.os.Message;
import  android.support.v7.app.AppCompatActivity;
 
public  class  MainActivity  extends  AppCompatActivity {
 
     private  Handler handler1 ;
     private  Handler handler2 ;
 
     @Override
     protected  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
         new  MyThread1().start();
         new  MyThread2().start();
     }
 
     class  MyThread1  extends  Thread {
 
         @Override
         public  void  run() {
             super .run();
 
             Looper.prepare();
 
             handler1 =  new  Handler(){
                 @Override
                 public  void  handleMessage(Message msg) {
                     super .handleMessage(msg);
                     System.out.println(  "threadName--"  + Thread.currentThread().getName() +  "messageWhat-" + msg.what );
                 }
             };
 
             try  {
                 sleep(  3000  );
             catch  (InterruptedException e) {
                 e.printStackTrace();
             }
 
             handler2.sendEmptyMessage(  2  ) ;
 
             Looper.loop();
         }
     }
 
     class  MyThread2  extends  Thread {
         @Override
         public  void  run() {
             super .run();
             Looper.prepare();
 
             handler2 =  new  Handler(){
                 @Override
                 public  void  handleMessage(Message msg) {
                     super .handleMessage(msg);
                     System.out.println(  "threadName--"  + Thread.currentThread().getName() +  "messageWhat-" + msg.what );
                 }
             };
 
             try  {
                 sleep(  4000  );
             catch  (InterruptedException e) {
                 e.printStackTrace();
             }
 
             handler1.sendEmptyMessage(  5  ) ;
 
             Looper.loop();
         }
     }
}

  

注意:

1、调用Looper类的 prepare() 方法可以为当前线程创建一个消息循环,调用loop() 方法使之处理信息,直到循环结束。

2、Handler有几个构造重载,如果构造时不提供Looper类对象参数,会获取当前线程的Looper对象,即将当前线程的消息循环作为Handler关联的消息循环。

3、消息处理机制中,消息存放在一个消息队列中,而线程围绕这个队列进入一个无限循环,直到程序退出。

  如果队列中有消息,线程就会把消息取出来,并分发给相应的Handler进行处理;

   如果队列中没有消息,线程就会进入空闲等待状态,等待下一个消息的到来。


很明显的一点就是,我们要在子线程中调用Looper.prepare() 为一个线程开启一个消息循环,默认情况下Android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。) Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。 然后通过Looper.loop() 让Looper开始工作,从消息队列里取消息,处理消息。

注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。

然而这一切都可以用HandlerThread类来帮我们做这些逻辑操作。

HandlerThread

HandlerThread本质上就是一个普通Thread,只不过内部建立了Looper.

HandlerThread的常规用法

  • 创建一个HandlerThread

mThread = new HandlerThread("handler_thread");

  • 启动一个HandlerThread

    mThread.start();

  • 退出循环
    Looper是通过调用loop方法驱动着消息循环的进行: 从MessageQueue中阻塞式地取出一个消息,然后让Handler处理该消息,周而复始,loop方法是个死循环方法。

那如何终止消息循环呢?我们可以调用Looper的quit方法或quitSafely方法,二者稍有不同。

 /**
     * Quits the looper.
     * <p>
     * Causes the {@link #loop} method to terminate without processing any
     * more messages in the message queue.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p class="note">
     * Using this method may be unsafe because some messages may not be delivered
     * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
     * that all pending work is completed in an orderly manner.
     * </p>
     *
     * @see #quitSafely
     */
    public void quit() {
        mQueue.quit(false);
    }

    /**
     * Quits the looper safely.
     * <p>
     * Causes the {@link #loop} method to terminate as soon as all remaining messages
     * in the message queue that are already due to be delivered have been handled.
     * However pending delayed messages with due times in the future will not be
     * delivered before the loop terminates.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p>
     */
    public void quitSafely() {
        mQueue.quit(true);
    }

相同点:
将不在接受新的事件加入消息队列。

不同点
当我们调用Looper的quit方法时,实际上执行了MessageQueue中的removeAllMessagesLocked方法,该方法的作用是把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过sendMessageDelayed或通过postDelayed等方法发送的需要延迟执行的消息)还是非延迟消息。

当我们调用Looper的quitSafely方法时,实际上执行了MessageQueue中的removeAllFutureMessagesLocked方法,通过名字就可以看出,该方法只会清空MessageQueue消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler去处理,quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息。

无论是调用了quit方法还是quitSafely方法只会,Looper就不再接收新的消息。即在调用了Looper的quit或quitSafely方法之后,消息循环就终结了,这时候再通过Handler调用sendMessage或post等方法发送消息时均返回false,表示消息没有成功放入消息队列MessageQueue中,因为消息队列已经退出了。

需要注意的是Looper的quit方法从API Level 1就存在了,但是Looper的quitSafely方法从API Level 18才添加进来。

小例子:

package com.app;

import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private HandlerThread myHandlerThread ;
    private Handler handler ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //创建一个线程,线程名字:handler-thread
        myHandlerThread = new HandlerThread( "handler-thread") ;
        //开启一个线程
        myHandlerThread.start();
        //在这个线程中创建一个handler对象
        handler = new Handler( myHandlerThread.getLooper() ){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //这个方法是运行在 handler-thread 线程中的 ,可以执行耗时操作
                Log.d( "handler " , "消息: " + msg.what + "  线程: " + Thread.currentThread().getName()  ) ;

            }
        };

        //在主线程给handler发送消息
        handler.sendEmptyMessage( 1 ) ;

        new Thread(new Runnable() {
            @Override
            public void run() {
             //在子线程给handler发送数据
             handler.sendEmptyMessage( 2 ) ;
            }
        }).start() ;

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        //释放资源
        myHandlerThread.quit() ;
    }
}

运行效果:

/com.app D/handler: 消息: 1  线程: handler-thread
/com.app D/handler: 消息: 2  线程: handler-thread

HandlerThread的特点

  • HandlerThread将loop转到子线程中处理,说白了就是将分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅。

  • 开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。HandlerThread本质是一个线程,在线程内部,代码是串行处理的。

  • 但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。

  • HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。

  • 对于网络IO操作,HandlerThread并不适合,因为它只有一个线程,还得排队一个一个等着。


猜你喜欢

转载自blog.csdn.net/qq_30295213/article/details/78272551