HandlerThread是能够新建拥有Looper的Thread,这个Looper能够用来新建其他的Handler。HandlerThread本质是一个线程,在线程内部,代码是串行处理的。(线程中的Looper)需要注意的是,新建的时候需要被回调。
1.2 特点(1) HandlerThread将loop转到子线程中处理,目的就是分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅。
(2)开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。
(3)但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。
(4)HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。
HandlerThread继承自Thread,一般适应的场景,便是集Thread和Handler之所长,适用于会长时间在后台运行,并且间隔时间内(或适当情况下)会调用的情况,比如上面所说的实时更新。其实使用HandlerThread的效果和使用Thread+Handler差不多。不过后者对开发者的要求更高。
在我的另一篇博客详细应用:Android性能优化之详解IntentService
Handler会关联一个单独的线程、Looper和消息队列;他默认关联主线程,如果要在其他线程执行,可以使用HandlerThread。
HandlerThread继承于Thread,所以它本质就是个Thread。它与普通Thread的差别就在于:建立了一个Thread,有自己的Looper和创立了消息队列,可以让在自己的线程中分发和处理消息。
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; } } }}
5 参考链接 Android系统分析之异步消息处理机制-Message/Handler/MessageQueue/Looper
Android HandlerThread 完全解析
Android HandlerThread 总结使用
Android ——对HandlerThread的理解和注意事项
总结以上是内存溢出为你收集整理的Android性能优化之实现拥有Looper的线程--HandlerThread全部内容,希望文章能够帮你解决Android性能优化之实现拥有Looper的线程--HandlerThread所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)