HandlerThread(详细例子)

HandlerThread是什么

官方解释

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.

方便我们创建一个拥有looper的线程

HandlerThread继承自Thread,因此HandlerThread其实就是一个线程。
线程开启时也就是run方法运行起来后,线程同时创建一个含有消息队列的looper,并对外提供自己这个对象的get方法,这就是和普通的Thread不一样的地方。可用于多个耗时任务要串行执行

如果对handler不熟的话,可以先看这个Handler介绍


使用流程

  1. 实例对象,参数为线程名字
HandlerThread handlerThread = new HandlerThread("handlerThread");
  1. 启动线程
handlerThread.start();
  1. 实例主线程的Handler,参数为HandlerThread内部的一个looper.
    Handler handler = new Handler(handlerThread.getLooper()) {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };

看个简单的例子

里面打了挺多的注释,Log日志也用序号标明了顺序。这里模拟的情况是我们在子线程下载东西,然后和主线程之间进行通信。主线程知道了下载开始和下载结束的时间,也就能及时改变界面UI。

首先是DownloadThread类,继承于HandlerThread,用于下载。

public class DownloadThread extends HandlerThread{

    private static final String TAG = "DownloadThread";

    public static final int TYPE_START = 2;//通知主线程任务开始
    public static final int TYPE_FINISHED = 3;//通知主线程任务结束

    private Handler mUIHandler;//主线程的Handler

    public DownloadThread(String name) {
        super(name);
    }

    /*
    * 执行初始化任务
    * */
    @Override
    protected void onLooperPrepared() {
        Log.e(TAG, "onLooperPrepared: 1.Download线程开始准备");
        super.onLooperPrepared();
    }

    //注入主线程Handler
    public void setUIHandler(Handler UIhandler) {
        mUIHandler = UIhandler;
        Log.e(TAG, "setUIHandler: 2.主线程的handler传入到Download线程");
    }

    //Download线程开始下载
    public void startDownload() {
        Log.e(TAG, "startDownload: 3.通知主线程,此时Download线程开始下载");
        mUIHandler.sendEmptyMessage(TYPE_START);

        //模拟下载
        Log.e(TAG, "startDownload: 5.Download线程下载中...");
        SystemClock.sleep(2000);

        Log.e(TAG, "startDownload: 6.通知主线程,此时Download线程下载完成");
        mUIHandler.sendEmptyMessage(TYPE_FINISHED);
    }
}


然后是MainActivity部分。

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private DownloadThread mHandlerThread;//子线程
    private Handler mUIhandler;//主线程的Handler

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

        //初始化,参数为线程的名字
        mHandlerThread = new DownloadThread("mHandlerThread");
        //调用start方法启动线程
        mHandlerThread.start();
        //初始化Handler,传递mHandlerThread内部的一个looper
        mUIhandler = new Handler(mHandlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                //判断mHandlerThread里传来的msg,根据msg进行主页面的UI更改
                switch (msg.what) {
                    case DownloadThread.TYPE_START:
                    	//不是在这里更改UI哦,只是说在这个时间,你可以去做更改UI这件事情,改UI还是得在主线程。
                        Log.e(TAG, "4.主线程知道Download线程开始下载了...这时候可以更改主界面UI");
                        break;
                    case DownloadThread.TYPE_FINISHED:
                        Log.e(TAG, "7.主线程知道Download线程下载完成了...这时候可以更改主界面UI,收工");
                        break;
                    default:
                        break;
                }
                super.handleMessage(msg);
            }
        };
        //子线程注入主线程的mUIhandler,可以在子线程执行任务的时候,随时发送消息回来主线程
        mHandlerThread.setUIHandler(mUIhandler);
        //子线程开始下载
        mHandlerThread.startDownload();
    }

    @Override
    protected void onDestroy() {
        //有2种退出方式
        mHandlerThread.quit();
        //mHandlerThread.quitSafely(); 需要API>=18
        super.onDestroy();
    }
}

运行的Log日志如下

HandlerThread(详细例子)_第1张图片


注意

这个使用的顺序是不能更改的!!!,因为如果不先让子线程start起来,那么创建主线程的handler的参数getLooper是获取不到的,这一点可以看源码就清楚。

完整的源码介绍可以参考这一篇

    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        synchronized (this) {
            while (isAlive() && mLooper == null) {//循环等待
                try {
                    wait();//mLooper为空的话,我们getLooper不到的,必须先给mLooper赋值 
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();        
        synchronized (this) {
            mLooper = Looper.myLooper();//这里赋值了,调用start() 后就会执行此方法
            notifyAll();  
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();    
        Looper.loop();     
        mTid = -1;
    }

感谢
https://blog.csdn.net/u011240877/article/details/72905631
https://blog.csdn.net/userzhanghao123/article/details/51683403

你可能感兴趣的:(Android)