Android效能優化之實現擁有Looper的執行緒--HandlerThread
1 HandlerThread
1.1 定義
HandlerThread是能夠新建擁有Looper的Thread,這個Looper能夠用來新建其他的Handler。HandlerThread本質是一個執行緒,線上程內部,程式碼是序列處理的。(執行緒中的Looper)需要注意的是,新建的時候需要被回撥。
1.2 特點
(1) HandlerThread將loop轉到子執行緒中處理,目的就是分擔MainLooper的工作量,降低了主執行緒的壓力,使主介面更流暢。
(2)開啟一個執行緒起到多個執行緒的作用。處理任務是序列執行,按訊息傳送順序進行處理。
(3)但是由於每一個任務都將以佇列的方式逐個被執行到,一旦佇列中有某個任務執行時間過長,那麼就會導致後續的任務都會被延遲處理。
(4)HandlerThread擁有自己的訊息佇列,它不會干擾或阻塞UI執行緒。
1.3 應用場景
HandlerThread繼承自Thread,一般適應的場景,便是集Thread和Handler之所長,適用於會長時間在後臺執行,並且間隔時間內(或適當情況下)會呼叫的情況,比如上面所說的實時更新。其實使用HandlerThread的效果和使用Thread+Handler差不多。不過後者對開發者的要求更高。
在我的另一篇部落格詳細應用:Android效能優化之詳解IntentService
1.4 Handler、Thread和HandlerThread的差別
Handler會關聯一個單獨的執行緒、Looper和訊息佇列;他預設關聯主執行緒,如果要在其他執行緒執行,可以使用HandlerThread。
HandlerThread繼承於Thread,所以它本質就是個Thread。
2 HandlerThread原始碼分析
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
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) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* 此方法返回與此執行緒關聯的Looper。
* 如果這個執行緒沒有被啟動,或者由於任何原因isAlive()返回false,這個方法將返回null。
* 如果這個執行緒已經啟動,這個方法將被阻塞,直到活套被初始化。
* @return The 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 {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/**
* Returns the identifier of this thread.
*/
public int getThreadId() {
return mTid;
}
}
3 使用例子
3.1 例子
public class HandlerThreadActivity extends AppCompatActivity {
private TextView mTvServiceInfo;
private static final int MSG_UPDATE_INFO = 0x110;
private boolean isUpdateInfo;
private HandlerThread mCheckMsgThread;
//使用HandlerThread執行緒的looper建立的mCheckMsgHandler
private Handler mCheckMsgHandler;
//主執行緒建立的mHandler來更新ui.
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread_handler);
//建立後臺執行緒
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, 1000);
}
}
};
}
/**
* 模擬從伺服器解析資料
*/
private void checkForUpdate() {
try {
//模擬耗時
Thread.sleep(1000);
mHandler.post(new Runnable() {
@Override
public void run() {
String result = "實時更新中,當前大盤指數:<font color='red'>%d</font>";
result = String.format(result, (int) (Math.random() * 3000 + 1000));
mTvServiceInfo.setText(Html.fromHtml(result));
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//釋放資源
mCheckMsgThread.quit();
}
}
3.2 執行效果
4 解決一個需求
4.1 問題提出
在子執行緒中開啟相機,並且在子執行緒中預覽回撥(編碼),如何實現?
4.2 子執行緒中的方法執行在子執行緒還是UI執行緒
public class ThreadTest {
static class MyTask extends Thread {
@Override
public void run() {//只有run方法屬於子執行緒
System.out.println(Thread.currentThread().getName() + " _run");
}
void onPreviewFrame(){//在UI執行緒執行
System.out.println(Thread.currentThread().getName() + " _onPreviewFrame");
}
}
public static void main(String[] args) {
//子執行緒
MyTask task = new MyTask();
task.start();
//在UI執行緒執行
task.onPreviewFrame();
}
}
4.3 方法對比
4.3.1 普通執行緒與Camera
非同步任務(AsyncTask)的Looper(因為子執行緒沒建立looper),使用的MainLooper。
public class AsyncTaskActivity1 extends Activity implements Callback {
static final String TAG = "guan";
Camera mCamera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
byte[] buffers;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread2);
surfaceView = (SurfaceView) findViewById(R.id.surface_view);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
new MyTask().execute();
}
class MyTask extends AsyncTask<Void, Void, Void> implements PreviewCallback{
@Override
protected Void doInBackground(Void... params) {
//子執行緒中開啟
Log.e(TAG, Thread.currentThread().getName() + "_open");
mCamera = Camera.open(CameraInfo.CAMERA_FACING_BACK);
try {
mCamera.setPreviewDisplay(surfaceHolder);
} catch (IOException e) {
e.printStackTrace();
}
Camera.Parameters parameters = mCamera.getParameters();
//設定相機引數
parameters.setPreviewSize(480, 320); //預覽畫面寬高
mCamera.setParameters(parameters);
//獲取預覽影象資料
buffers = new byte[480 * 320 * 4];
mCamera.addCallbackBuffer(buffers);
mCamera.setPreviewCallbackWithBuffer(this);
mCamera.startPreview();
Log.d(TAG, Thread.currentThread().getName()+ "_doInBackground");
return null;
}
//畫面預覽的回撥
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
if(mCamera != null){
mCamera.addCallbackBuffer(buffers);
//編碼
Log.d(TAG, Thread.currentThread().getName()+ "_onPreviewFrame");
}
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
列印結果:
結果表明:畫面預覽的回撥方法onPreviewFrame()在UI執行緒中執行,未實現需求要求。
4.3.2 HandlerThread執行緒與Camera
public class HandlerThreadActivity4 extends Activity implements Callback {
static final String TAG = "guan";
Camera mCamera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
byte[] buffers;
HandlerThread mHandlerThread;
Handler subHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread2);
surfaceView = (SurfaceView) findViewById(R.id.surface_view);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mHandlerThread = new HandlerThread("my_handlerthread");
mHandlerThread.start();
subHandler = new Handler(mHandlerThread.getLooper());
subHandler.post(new MyTask());
}
class MyTask implements Runnable, PreviewCallback{
@SuppressLint("NewApi") @Override
public void run() {
//開啟相機
//子執行緒中開啟
Log.d("guan", Thread.currentThread().getName() + "_open");
mCamera = Camera.open(CameraInfo.CAMERA_FACING_BACK);
try {
mCamera.setPreviewDisplay(surfaceHolder);
} catch (IOException e) {
e.printStackTrace();
}
Camera.Parameters parameters = mCamera.getParameters();
//設定相機引數
parameters.setPreviewSize(480, 320); //預覽畫面寬高
mCamera.setParameters(parameters);
//獲取預覽影象資料
buffers = new byte[480 * 320 * 4];
mCamera.addCallbackBuffer(buffers);
mCamera.setPreviewCallbackWithBuffer(this);
mCamera.startPreview();
Log.d(TAG, Thread.currentThread().getName()+ "_run");
}
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
if(mCamera != null){
mCamera.addCallbackBuffer(buffers);
//編碼
Log.d(TAG, Thread.currentThread().getName()+ "_onPreviewFrame");
}
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
列印結果:
結果表明:畫面預覽的回撥方法onPreviewFrame()在子執行緒中執行,完美實現需求要求。
4.3.3 解析原因–Camera原始碼
new Camera -> looper -> EventHandler.handleMessage -> onPreviewFrame
public class Camera {
private int cameraInitVersion(int cameraId, int halVersion) {
mShutterCallback = null;
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
mPostviewCallback = null;
mUsingPreviewAllocation = false;
mZoomListener = null;
Looper looper;
if ((looper = Looper.myLooper()) != null) {//Handler執行緒Looper
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {//UI執行緒Looper
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
return native_setup(new WeakReference<Camera>(this), cameraId, halVersion,
ActivityThread.currentOpPackageName());
}
private class EventHandler extends Handler {
private final Camera mCamera;
public EventHandler(Camera c, Looper looper) {
super(looper);
mCamera = c;
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case CAMERA_MSG_PREVIEW_FRAME:
PreviewCallback pCb = mPreviewCallback;
if (pCb != null) {
if (mOneShot) {
mPreviewCallback = null;
} else if (!mWithBuffer) { setHasPreviewCallback(true, false);
}
//回撥onPreviewFrame()方法
//onPreviewFrame的執行,在Camera所持有的Looper執行緒中執行
pCb.onPreviewFrame((byte[]) msg.obj, mCamera);
}
return;
}
}
}
}