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。它与普通Thread的差别就在于:建立了一个Thread,有自己的Looper和创立了消息队列,可以让在自己的线程中分发和处理消息。
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;
}
}
}
}