天天看點

Android多線程(HandlerThread篇)使用原理分析

【齊天的部落格】轉載請注明出處(萬分感謝!):

https://blog.csdn.net/qijinglai/article/details/80735718

關聯文章:

Android多線程(Handler篇)

Android多線程(AsyncTask篇)

Android多線程(HandlerThread篇)

Android多線程(IntentService篇)

在之前Android多線程(Handler篇)中講解了ThreadLoacl、Looper、Handler、Message之間的關系,在主線程中為我們工作。其實我們可以借鑒UI線程Looper的思想,建一個子線程,也通過Handler、Looper通信,可以适用于很多場景。

主線程中是自帶looper的,而在子線程中使用Handler需要自己建立looper,而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.
           

意思是,使用HandlerThread可以友善的開啟一個線程,并且這個線程已經綁定了一個looper了。這個looper可以用來new一個handler類。注意在此之前,要調用start()方法。

很顯然HandlerThread可以勝任我們提到的工作。

使用

這裡就直接複制鴻洋_寫的例子了

import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.text.Html;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {


    private TextView mTvServiceInfo;

    private HandlerThread mCheckMsgThread;
    private Handler mCheckMsgHandler;
    private boolean isUpdateInfo;

    private static final int MSG_UPDATE_INFO = ;

    //與UI線程管理的handler
    private Handler mHandler = new Handler();


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

        //建立背景線程
        initBackThread();

        mTvServiceInfo = (TextView) findViewById(R.id.id_textview);

    }

    @Override
    protected void onResume()
    {
        super.onResume();
        //開始查詢
        isUpdateInfo = true;
        mCheckMsgHandler.sendEmptyMessage(MSG_UPDATE_INFO);
    }

    @Override
    protected void onPause()
    {
        super.onPause();
        //停止查詢
        isUpdateInfo = false;
        mCheckMsgHandler.removeMessages(MSG_UPDATE_INFO);

    }

    private void initBackThread()
    {
        mCheckMsgThread = new HandlerThread("check-message-coming");
        mCheckMsgThread.start();
        mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper())
        {
            @Override
            public void handleMessage(Message msg)
            {
                checkForUpdate();
                if (isUpdateInfo)
                {
                    mCheckMsgHandler.sendEmptyMessageDelayed(MSG_UPDATE_INFO, );
                }
            }
        };


    }

    /**
     * 模拟從伺服器解析資料
     */
    private void checkForUpdate()
    {
        try
        {
            //模拟耗時
            Thread.sleep();
            mHandler.post(new Runnable()
            {
                @Override
                public void run()
                {
                    String result = "實時更新中,目前大盤指數:<font color='red'>%d</font>";
                    result = String.format(result, (int) (Math.random() *  + ));
                    mTvServiceInfo.setText(Html.fromHtml(result));
                }
            });

        } catch (InterruptedException e)
        {
            e.printStackTrace();
        }

    }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        //釋放資源
        mCheckMsgThread.quit();
    }
}
           

布局就是一個TextView。

使用并不是本文重點,下面分析源碼。

原理分析

HandlerThread使用一共三步

mCheckMsgThread = new HandlerThread("check-message-coming");
 mCheckMsgThread.start(); 
 mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper())
 ...
 ...
           

構造,開啟,建立

  • 構造
public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
           

隻是調用了父類的初始化方法開了一個線程

  • 開啟

    調用start()方法,啟動一個新線程,新線程會執行相應的run()方法:

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -;
    }
               

    在之前Android多線程(Handler篇)中可以知道:

    prepare()中建立了一個Looper對象,并放入ThreadLocal中,在Looper對象的構造過程中,初始化了并綁定了一個MessageQueue。

    loop()方法不斷的循環從MessageQueue中取消息處理,當沒有消息的時候會阻塞,有消息的到來的時候會喚醒。

  • 建立
    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 {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
               
    傳回了剛剛在run()中建立的mLooper對象

最後值得說一下的是run()中的notifyAll()和getLooper()中的wait();

因為Handler是在主線程初始化的,是以必須等mLooper建立完成才能getLooper(),是以當mLooper==null時getLoop等待一下mLooper初始化,得到以後notifyAll。