Android性能优化之实现拥有Looper的线程--HandlerThread

Android性能优化之实现拥有Looper的线程--HandlerThread,第1张

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

总结

以上是内存溢出为你收集整理的Android性能优化之实现拥有Looper的线程--HandlerThread全部内容,希望文章能够帮你解决Android性能优化之实现拥有Looper的线程--HandlerThread所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/1013245.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-22
下一篇 2022-05-22

发表评论

登录后才能评论

评论列表(0条)