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。它与普通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;
            }
        }
    }
}

5 参考链接

Android系统分析之异步消息处理机制-Message/Handler/MessageQueue/Looper

Android HandlerThread 完全解析

Android HandlerThread 总结使用

Android ——对HandlerThread的理解和注意事项

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值