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的理解和注意事项

0 0
原创粉丝点击