Android性能优化之实现一个线程多个任务--HandlerThread
来源:互联网 发布:淘宝助手怎么上传宝贝 编辑:程序博客网 时间:2024/06/05 10:48
1 概念
Message/Handler/MessageQueue/Looper之间的关系请在此学习
Android系统分析之异步消息处理机制-Message/Handler/MessageQueue/Looper
1.1 HandlerThread应用场景
因为HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程,比较合适处理那些需要花费时间偏长的任务。我们只需要把任务发送给HandlerThread,然后就只需要等待任务执行结束的时候通知返回到主线程就好了。
1.2 HandlerThread的特点
(1)HandlerThread将loop转到子线程中处理,目的就是分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅。
(2)开启一个线程起到多个线程的作用。处理任务是串行执行,按消息发送顺序进行处理。HandlerThread本质是一个线程,在线程内部,代码是串行处理的。
(3)但是由于每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。
(4)HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。
(5)对于网络IO操作,HandlerThread并不适合,因为它只有一个线程,还得排队一个一个等着。
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; } /** * 构造函数,并设置线程的优先级 * @param name * @param priority The priority to run the thread at. The value supplied must be from * {@link android.os.Process} and not from java.lang.Thread. */ public HandlerThread(String name, int priority) { super(name); mPriority = priority; } /** * Call back method that can be explicitly overridden if needed to execute some * setup before Looper loops. */ 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; } /** * This method returns the Looper associated with this thread. If this thread not been started * or for any reason is isAlive() returns false, this method will return null. If this thread * has been started, this method will block until the looper has been initialized. * @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; } /** * Quits the handler thread's looper. */ 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. See Process.myTid(). */ public int getThreadId() { return mTid; }}
3 使用例子
public class HandlerThread_UIActivity3 extends Activity { private TextView mTvServiceInfo; private boolean isUpdateInfo; private static final int Msg_ONE = 0x001; private static final int Msg_TWO = 0x110; private HandlerThread handlerThread;//handlerThread private Handler subHandler;//子线程Handler private Handler uiHandler = new Handler();//UI线程Handler @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler_ui_thread3); mTvServiceInfo = (TextView) findViewById(R.id.id_textview); //创建后台线程 handlerThread = new HandlerThread("subHandlerThread"); handlerThread.start(); uiHandler = new Handler(); subHandler = new Handler(handlerThread.getLooper(), subCallback); } /** * 处理HandlerThread的回调消息:开启一个线程起到多个线程的作用 * * 该接口的实现就是处理异步耗时任务的,因此该方法执行在子线程中 */ private Handler.Callback subCallback = new Handler.Callback() { @Override public boolean handleMessage(Message msg) { switch (msg.what) { case Msg_ONE: checkForUpdate();//子线程执行任务 if (isUpdateInfo) { subHandler.sendEmptyMessageDelayed(Msg_ONE, 1000); } break; case Msg_TWO: Toast.makeText(HandlerThread_UIActivity3.this,"Msg_TWO收到消息",Toast.LENGTH_SHORT).show();// mTvServiceInfo.setText("子线程更新UI崩溃"); break; default: break; } return false; } }; /** * 子线程执行任务-模拟从服务器解析数据 */ private void checkForUpdate() { try { Thread.sleep(1000);//模拟耗时 //使用UI线程Handler更新UI uiHandler.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 onResume() { super.onResume(); //开始查询 isUpdateInfo = true; subHandler.sendEmptyMessage(Msg_ONE); } @Override protected void onPause() { super.onPause(); //停止查询 isUpdateInfo = false; subHandler.removeMessages(Msg_ONE); } @Override protected void onDestroy() { super.onDestroy(); handlerThread.quit();//释放资源 }}
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 HandlerThread 完全解析
Android HandlerThread 总结使用
Android ——对HandlerThread的理解和注意事项
- Android性能优化之实现一个线程多个任务--HandlerThread
- Android 线程之HandlerThread
- Android性能优化之使用线程池处理异步任务
- Android性能优化之使用线程池处理异步任务
- Android性能优化之使用线程池处理异步任务
- Android性能优化之使用线程池处理异步任务
- Android性能优化之使用线程池处理异步任务
- Android性能优化之使用线程池处理异步任务
- Android性能优化之使用线程池处理异步任务
- Android 性能优化之使用线程池处理异步任务
- Android性能优化之使用线程池处理异步任务
- Android 性能优化之使用线程池处理异步任务
- Android性能优化之使用线程池处理异步任务
- Android 性能优化之使用线程池处理异步任务
- Android性能优化之使用线程池处理异步任务
- Android性能优化之使用线程池处理异步任务
- Android 性能优化之使用线程池处理异步任务
- Android 性能优化之使用线程池处理异步任务
- CentOS7 vs CentOS 6的不同之处
- RabbitMQ(五)—路由选择
- 5.2 服务端开发
- VMware怎么安装VMware tools
- 谈一谈Elasticsearch的集群部署
- Android性能优化之实现一个线程多个任务--HandlerThread
- MySQL-Join
- Android网络定位或GPS定位
- 小白 android build类 小结
- PHP文件操作-读取数据库文件路径复制到另一个目录
- Java StringBuffer和StringBuilder类
- Android Studio2.0应用结构解析
- 获取状态栏高度的方法
- vim 基本操作