美文网首页
HandlerThread总结

HandlerThread总结

作者: 李小神不偷懒 | 来源:发表于2018-03-08 19:02 被阅读0次

    使用场景

    程序需要执行一系列的耗时任务,这时候就需要启动额外的线程去执行耗时任务。如果每次遇到耗时任务都直接创建线程(new Thread() ),那么一系列耗时任务就要创建一系列线程,这些线程在任务完成后被系统回收销毁,并没有得到重复利用,造成资源浪费,增加系统负担。为此,可以使用HandlerThread在同一个线程中执行UI线程的异步任务。

    demo

    界面上2个按钮点击后执行耗时任务后,输出相应信息。


    HandlerThreadDemo.png
    public class HandlerThreadDemoActivity extends AppCompatActivity{
        private static final String TAG = "HandlerThreadActivity";
        private Button mBtnRequest1,mBtnRequest2;
        private MyHandler mMyHandler;
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_handlerthread);
            mBtnRequest1 = findViewById(R.id.btn_request1);
            mBtnRequest1.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(mMyHandler != null){
                        String info = "MessageFrom1:" + System.currentTimeMillis();
                        Log.d(TAG, "==> onClick: sendMsg1");
                        //发送消息1
                        Message msg = mMyHandler.obtainMessage(1,info);
                        mMyHandler.sendMessage(msg);
                    }
                }
            });
            mBtnRequest2 = findViewById(R.id.btn_request2);
            mBtnRequest2.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(mMyHandler != null){
                        String info = "MessageFrom2:" + System.currentTimeMillis();
                        Log.d(TAG, "==> onClick: sendMsg2");
                        //发送消息2
                        Message msg = mMyHandler.obtainMessage(2,info);
                        mMyHandler.sendMessage(msg);
                    }
                }
            });
            HandlerThread t1 = new HandlerThread("t1");
            t1.start();
            mMyHandler = new MyHandler(t1.getLooper());
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            Log.d(TAG, "==> onStop: ");
            mMyHandler.removeCallbacksAndMessages(null);
        }
    
        static class MyHandler extends Handler{
            MyHandler(Looper looper){
                super(looper);
            }
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what){
                    case 1:
                        try {
                            //消息1对应的耗时操作,模拟5s
                            Thread.sleep(5000);
                            Log.d(TAG, "==> handleMessage: msg1.");
                            showMessageInfo(((String) msg.obj));
                        }catch (InterruptedException e){
                            Log.d(TAG, "==> handleMessage: interruptedBy1");
                        }
                        break;
                    case 2:
                        try {
                             //消息1对应的耗时操作,模拟2s
                            Thread.sleep(2000);
                            Log.d(TAG, "==> handleMessage: msg2.");
                            showMessageInfo(((String) msg.obj));
                        }catch (InterruptedException e){
                            Log.d(TAG, "==> handleMessage: interruptedBy2");
                        }
                        break;
                }
            }
            
            //输出处理完成消息
            private void showMessageInfo(String message){
                Log.d(TAG, "==> showMessageInfo:thread = " + Thread.currentThread().getName()
                        + " message = " + message);
            }
        }
    }
    

    点击按钮1立即点击按钮2输出如下日志。先处理消息1的任务,耗时5s;尽管消息2早已发送,但对于消息2的处理在消息1处理完成之后。

    03-08 03:18:25.915 7669-7669/com.lss.alpha D/HandlerThreadActivity: ==> onClick: sendMsg1
    03-08 03:18:26.801 7669-7669/com.lss.alpha D/HandlerThreadActivity: ==> onClick: sendMsg2
    03-08 03:18:30.917 7669-7723/com.lss.alpha D/HandlerThreadActivity: ==> handleMessage: msg1.
    03-08 03:18:30.917 7669-7723/com.lss.alpha D/HandlerThreadActivity: ==> showMessageInfo:thread = t1 message = MessageFrom1:1520479105915
    03-08 03:18:32.921 7669-7723/com.lss.alpha D/HandlerThreadActivity: ==> handleMessage: msg2.
    03-08 03:18:32.921 7669-7723/com.lss.alpha D/HandlerThreadActivity: ==> showMessageInfo:thread = t1 message = MessageFrom2:1520479106801
    

    从日志可知:

    • 消息立即发出,并都在线程t1内执行了耗时任务,共用一个线程
    • 耗时任务按照消息收到的先后顺序依次执行。消息1处理时,后来的消息2的处理等待消息1处理完成后才能得到执行。

    源码

    public class HandlerThread extends Thread {
        int mPriority;
        int mTid = -1;
        Looper mLooper;
        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;
        }
        
        protected void onLooperPrepared() {
        }
    
        @Override
        public void run() {
            mTid = Process.myTid();
            Looper.prepare();
            synchronized (this) {
                //获得当前线程的Looper
                mLooper = Looper.myLooper();
                notifyAll();
            }
            Process.setThreadPriority(mPriority);
            onLooperPrepared();
            //开始轮询获得消息
            Looper.loop();
            mTid = -1;
        }
    
        public Looper getLooper() {
            if (!isAlive()) {
                return null;
            }
            //Looper没有创建,阻塞
            synchronized (this) {
                while (isAlive() && mLooper == null) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
            return mLooper;
        }
       ....
    }
    

    从源码可以得知,HandlerThread创建了一个本地Looper对象,通过Handler向Looper的消息队列发送消息,Looper依次轮询消息队列中的消息,并在当前线程中调用消息的处理(耗时任务)。

    操作

    1. 实例化HandlerThread,并调用start()方法开启线程
    2. 获得Looper对象,出入Looper对象实例化Handler
    3. Handler发送消息
    4. Handler在HandlerThread中处理消息

    总结

    HanderThread一个具有Looper的线程,可以按照消息的时间(msg.when)依次执行耗时任务。

    • 优点: 不会堵塞主线程,减少对性能的消耗
    • 缺点: 串行执行任务,处理效率比较低

    相关文章

      网友评论

          本文标题:HandlerThread总结

          本文链接:https://www.haomeiwen.com/subject/sbwefftx.html