android-handlerThread

时间:2024-06-01 10:32:35

记住一点Handler是子线程到主线程,HandlerThread是主线程到子线程通信

一、HandlerThread简介

HandlerThread是一个轻量级的异步类,可以实现多线程,并且可以实现线程间的通信(HandlerThread主要应用是实现主线程到子线程的通信,子线程到主线程通信可以通过Handler机制)

二、HandlerThread原理

既然已经有Handler可以实现线程间通信,为什么又设计了HandlerThread?

HandlerThread通过字面意思我们可以看到,它是Handler+Thread,那么我们猜测它应该实现了Handler和Thread功能,到底是不是呢,我们向下看。

首先,HandlerThread继承了Thread类,也就是说HandlerThread可以创建一个新的线程。

其次,HandlerThread内封装了Handler类,并自动创建了Looper和MessageQueue,也就是说我们使用HandlerThread线程时,不需要手动创建Looper。

优点:

之前我们使用Handler时,必须自己创建线程,并且自己创建Looper等相关的功能,而HandlerThread则提供了一种方便的方式,相当于内部已经集成了这些功能,不需要我们再手动创建Looper。

三、HandlerThread使用实例

使用步骤:

使用步骤:
//1、创建HandlerThread对象,即创建了一个新的线程,参数为线程名,仅仅是标记线程用的
     HandlerThread mHandlerThread = new HandlerThread("mHandlerThread");
//2、开启线程,第一步创建了一个新的线程,此处开启线程。
    mHandlerThread.start();
//3、创建Handler,并重写handleMessage()方法
    //new Handler(mHandlerThread.getLooper()),即把该Handler绑定到mHandlerThread线程的Looper,
    //进而绑定到了线程mHandlerThread
     Handler mHandlerInHandlerThread = new Handler(mHandlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg) { 这个是在子线程
             //对信息的相关处理操作               
                //在子线程mHandlerThread中运行   
                super.handleMessage(msg);
            }
        };
//4、创建消息并发送消息
    //在主线程中
    Message msg = Message.obtain();
    //主线程向子线程mHandlerThread发送消息通信
    mHandlerInHandlerThread.sendMessage(msg);
//5、结束线程。之前开启线程,当工作结束不再使用该线程时,应该结束该线程
    //即停止了线程的消息循环
    mHandlerThread.quit();
通过使用步骤我们可以看到,HandlerThread实现的功能主要就是主线程向子线程通信,另外可以在使用Handler实现子线程到主线程的通信,进而就可以实现主线程到子线程间的双向通信.

使用实例:

使用实例:
//功能介绍:点击按钮实现延时操作,延时时间到后更新UI。
public class MainActivity extends AppCompatActivity {
     TextView mTxtShowTest;
     Button  mBtnInnerClass ,mBtnHandlerThread, mBtnQuit;
 
    //1、创建HandlerThread对象,即创建了一个新的线程,参数为线程名,仅仅是标记线程用的
    HandlerThread mHandlerThread = new HandlerThread("mHandlerThread");
 
    //匿名内部类,用于子线程向主线程通信用
    private Handler mhandlerInnerClass =  new Handler(){
        @Override
        public void handleMessage(Message msg) {
          super.handleMessage(msg);
            switch (msg.what){
                case 1:
                    //执行的UI操作
                    mTxtShowTest.setText("点击了mBtnInnerClass");
                    break;
                case 2:
                    //执行的UI操作
                    mTxtShowTest.setText("来自于mHandlerInHandlerThread的请求更新");
                    break;
            }
        }
    };
   @Override
   protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        mTxtShowTest = (TextView) findViewById(R.id.mTxtShowTest); 
        mBtnInnerClass = (Button) findViewById(R.id.mBtnInnerClass); 
        mBtnHandlerThread = (Button) findViewById(R.id.mBtnHandlerThread);
        mBtnQuit = (Button) findViewById(R.id.mBtnQuit);
 
        //2、开启线程,第一步创建了一个新的线程,此处开启线程。
         mHandlerThread.start();
 
        //3、创建Handler,并重写handleMessage()方法
        //new Handler(mHandlerThread.getLooper()),即把该Handler绑定
        //到了mHandlerThread线程的Looper,进而绑定到了线程mHandlerThread
        final Handler mHandlerInHandlerThread = new Handler(mHandlerThread.getLooper()){
                    @Override
            public void handleMessage(Message msg) {
               //已经是在子线程mHandlerThread中运行了
                //可以进行一些耗时等操作
                try{
                     Thread.sleep(10000);  //延时操作
                }catch (Exception e){
                    e.getMessage();
                }
 
                //子线程向主线程通信
                Message msg1 = Message.obtain(); 
         msg1.what = 2;
                mhandlerInnerClass.sendMessage(msg1);
 
                super.handleMessage(msg);
            }
         };
 
         mBtnInnerClass.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() { 
                        Message msg = Message.obtain(); 
                        msg.what = 1;
                        mhandlerInnerClass.sendMessage(msg);
                    } 
                }).start();
            }
         });
 
         mBtnHandlerThread.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //4、创建消息并发送消息
                //主线程中
                Message msg = Message.obtain();
                //主线程向子线程发送信息,通信
                mHandlerInHandlerThread.sendMessage(msg);
            }
        });
 
        mBtnQuit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                  //5、结束线程。之前开启线程,当工作结束不再使用该线程时,应该结束该线程
                  //即停止了线程的消息循环
                    mHandlerThread.quit();
            }
        });
    }
}
注意:

当连续多次点击按钮mBtnHandlerThread是,mTxtShowTest中显示,并不是同时显示的,而是先显示第一次,间隔延时10s(这个10s是在复写handleMessage()方法时自己写的 Thread.sleep(10000))后显示第二次,再间隔延时的10s显示第三次。当我们连续多次点击mBtnHandlerThread按钮时,消息入队列,取出消息执行时,有一个延时10s,之后更新UI,这个消息才算执行完成,然后从消息队列中取出下一个消息,同样有一个延时10s,之后才是更新UI,所以即便时快速连续多次点击按钮,但是执行时每次都间隔一个延时10s.

总结:

以上就是HandlerThread的使用步骤和使用实例,已经测试过可以使用。首先点击按钮mBtnInnerClass, mTxtShowTest显示"点击了mBtnInnerClass",之后再点击按钮mBtnHandlerThread,十秒之后,mTxtShowTest显示"来自于mHandlerInHandlerThread的请求更新"。多次点击按钮mBtnHandlerThread,然后点击mBtnInnerClass,mTxtShowTest显示"点击了mBtnInnerClass",10s后mTxtShowTest显示"来自于mHandlerInHandlerThread的请求更新",之后再点击mBtnInnerClass,mTxtShowTest显示"点击了mBtnInnerClass",10s后又会mTxtShowTest显示"来自于mHandlerInHandlerThread的请求更新",即可证明前面注意中说明的问题。

四、HandlerThread源码分析

在第三部分使用实例中的使用步骤可以看到,使用HandlerThread大概需要5步,具体如下:

使用步骤:
//1、创建HandlerThread对象,即创建了一个新的线程,参数为线程名,仅仅是标记线程用的
     HandlerThread mHandlerThread = new HandlerThread("mHandlerThread");
//2、开启线程,第一步创建了一个新的线程,此处开启线程。
    mHandlerThread.start();
//3、创建Handler,并重写handleMessage()方法
    //new Handler(mHandlerThread.getLooper()),即把该Handler绑定到mHandlerThread线程的Looper,
    //进而绑定到了线程mHandlerThread
     Handler mHandlerInHandlerThread = new Handler(mHandlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {
             //对信息的相关处理操作               
                //在子线程mHandlerThread中运行   
                super.handleMessage(msg);
            }
        };
//4、创建消息并发送消息
    //在主线程中
    Message msg = Message.obtain();
    //主线程向子线程mHandlerThread发送消息通信
    mHandlerInHandlerThread.sendMessage(msg);
//5、结束线程。之前开启线程,当工作结束不再使用该线程时,应该结束该线程
    //即停止了线程的消息循环
    mHandlerThread.quit();
我们根据使用步骤 ,一步一步的去看源码。

步骤1、创建HandlerThread对象

源码分析:HandlerThread mHandlerThread = new HandlerThread("mHandlerThread");
/**
 * Handy class for starting a new thread that has a looper. The looper can then be 
 * used to create handler classes. Note that start() must still be called.
 */
//通过HandlerThread 的定义,其继承Thread ,可知HandlerThread 就是个线程
public class HandlerThread extends Thread {
    int mPriority;//优先级
    int mTid = -1;
    Looper mLooper;//当前线程的Looper
    private @Nullable Handler mHandler;
 
    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
 
   public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    ...
}
总结:

HandlerThread就是个线程,继承了Thread。创建HandlerThread 时,就相当于创建了一个新的线程,并设置了该线程的优先级。

步骤二、开启线程 mHandlerThread.start();

源码分析:
//Causes this thread to begin execution; the Java Virtual Machine
//calls the run method of this thread.
public synchronized void start() {...}
 
//调用mHandlerThread的start(),最终将调用mHandlerThread的run()方法。
    @Override
    public void run() {
        mTid = Process.myTid();//获取当前线程的ID
        Looper.prepare();//创建Looper和MessageQueue
        //通过锁机制,获取当前线程的Looper对象
        synchronized (this) {
            //获取当前线程的Looper对象
            mLooper = Looper.myLooper();
            //发送通知,已经获取当前线程的Looper对象
            //主要是在第三步创建Handler中的mHandlerThread.getLooper()内使用
            notifyAll();
        }
        Process.setThreadPriority(mPriority);//设置线程的优先级
        //主要是做一些开启消息循环前的准备工作 -->>分析1
        onLooperPrepared();
        //开启消息循环
        Looper.loop();
        mTid = -1;
    }
分析1: onLooperPrepared()
    /**
     * Call back method that can be explicitly overridden if needed to execute some
     * setup before Looper loops.
     */
    protected void onLooperPrepared() {
    }
总结:

第一步创建了线程,第二步开启该线程。开启线程时,会创建Looper和MessageQueue,成功后线程会进入消息循环,不断从消息队列中取出消息并分发消息。

步骤三、创建Handler,并重写handleMessage()方法

使用方法: 
Handler mHandlerInHandlerThread = new Handler(mHandlerThread.getLooper()){
            @Override
            public void handleMessage(Message msg) {
              //对信息的相关处理操作               
                 //在子线程mHandlerThread中运行   
                super.handleMessage(msg);
            }
        };
 
//创建Handler时传入Looper对象,此时Handler就与该Looper绑定,进而与Looper所在的线程也绑定
//获取当前线程(即mHandlerThread线程)的Looper对象
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                        //等待,直到mHandlerThread的run()方法创建了Looper
                        //并 notifyAll()发送通知
                        wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
总结:

复写handleMessage()方法,该方法是在子线程mHandlerThread中运行 ,而非主线程,要注意。因为是在子线程中,所以可以进行一些耗时相关的操作。另外,通过Handler机制,可以实现该子线程与主线程的通信,进而更新UI。

步骤四、创建消息并发送消息

 //在主线程中
     Message msg = Message.obtain();
 //主线程向子线程mHandlerThread发送消息通信
     mHandlerInHandlerThread.sendMessage(msg);
 //与Handler中的使用方法一样,就不多做介绍了。
步骤五、结束线程

//之前开启线程,当工作结束不再使用该线程时,应该结束该线程
//即停止了线程的消息循环
//源码分析:mHandlerThread.quit();
    public boolean quit() {
        //获取当前Looper
        Looper looper = getLooper();
        if (looper != null) {
            //调用Looper的quit()方法 -->>分析1
            looper.quit();
            return true;
        }
        return false;
    }
 
//分析1: looper.quit();
    public void quit() {
        //调用MessageQueue的quit()方法 -->>分析2
        mQueue.quit(false);
    }
//通过looper.quit()退出是一种不安全的退出方法,
//还有一种安全的退出方法,即looper.quitSafely();
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();//-->>分析a
            return true;
        }
        return false;
    }
//分析a looper.quitSafely()的源码实现:
    public void quitSafely() {
        //通过源码,截至到目前可以看出,安全不安全主要是mQueue.quit()方法
        //内的boolean变量是true还是false 
        mQueue.quit(true);// -->>分析2
    }
 
分析2: mQueue.quit(false);
    void quit(boolean safe) { 
        synchronized (this) {
            if (mQuitting) {
                    return;
            }
            mQuitting = true;
 
            if (safe) {//安全的退出方式
                    removeAllFutureMessagesLocked();// -->>分析4(请先看分析3)
            } else {//非安全的退出方式
                    removeAllMessagesLocked();// -->>分析3
            }
 
            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }
 
//分析3、 removeAllMessagesLocked()
    //不管该消息是否在使用,把消息队列中的所有消息都回收
    private void removeAllMessagesLocked() {
        Message p = mMessages;
        while (p != null) {
            Message n = p.next;
            //Recycles a Message that may be in-use.
            //这里,不管Message是否在使用,都回收销毁,
            //所以也就决定了它肯定是不安全的
            p.recycleUnchecked();
            p = n;
        }
        mMessages = null;
    }
 
 
//分析4、 removeAllFutureMessagesLocked()
//首先判断是否有消息再使用中,如果没有就按照分析3的方法全部回收,
//如果有消息正在使用中,这个使用的消息不做回收,它依然能够正常执行完成,
//而其他的所有的没有正在执行的全部回收
    private void removeAllFutureMessagesLocked() {
        //Returns milliseconds since boot, not counting time spent in deep sleep.
        final long now = SystemClock.uptimeMillis();
        Message p = mMessages;
        if (p != null) {
            if (p.when > now) {
               //判断消息队列现在是否正在处理消息,如果没有则直接把所有消息回收
               //通过时间来判定的
               removeAllMessagesLocked();
            } else {
                //有正在处理的消息,则处理完成后再退出
                Message n;
                for (;;) {
                    n = p.next;
                    if (n == null) {
                        return;
                    }
                    if (n.when > now) {
                        break;
                    }
                    p = n;
                }
                p.next = null;
                do {
                    p = n;
                    n = p.next;
                    p.recycleUnchecked();
                } while (n != null);
            }
        }
    }

总结:

所谓的安全与否,关键是对正在使用中的消息如何处理来判断的,如果直接回收消息就是不安全,等待它处理完成就是安全的。

五、总结

本文对HandlerThread做了全部分析,从原理、使用实例,到源码分析,希望对您有帮助。

 
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.****.net/haovin/article/details/89787721