Android面向面试复习----HandlerThread的妙用

HandlerThread的妙用

很多博客讲了HandlerThread的用法,但是没有具体的应用场景,可能也是了解并未真正使用!

1. HandlerThread是什么?

handlerThread是内部有一个looper轮询器的Thread线程。

  1. HandlerThread产生的背景

    google为了避免以下几种情况,给android开发者提供了这样一个异步框架

    • 在需要做子线程耗时操作时,我们有可能会new Thread来进行
    • 频繁多次创建子线程,对性能是有影响的
    • 可以自己在子线程中使用looper轮询,避免多次创建线程
  2. HandlerThread的特点
    • HandlerThread是一个线程类,它继承了Thread
    • 它的内部有自己的Looper对象,可以进行loop轮询
    • 使用HandlerThread的looper创建的Handler在handleMessage中可以进行耗时操作,因为它是执行在子线程的
    • 它的优点是不会阻塞主线程,缺点是不能同时执行多任务,需要有序执行,执行效率低。

2. HandlerThread如何使用

注意,指定优先级时,是指定进程的优先级,不是线程的优先级,可选值为:
public static final int THREAD_PRIORITY_DEFAULT = 0;
public static final int THREAD_PRIORITY_LOWEST = 19;
public static final int THREAD_PRIORITY_BACKGROUND = 10;
public static final int THREAD_PRIORITY_FOREGROUND = -2;
public static final int THREAD_PRIORITY_DISPLAY = -4;
public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8;
public static final int THREAD_PRIORITY_AUDIO = -16;

  1. 创建HandlerThread对象,指定名字和进程优先级
  2. 复写onLoopPrepared,进行准备工作
  3. 调用start开启HandlerThread线程轮询,执行任务
  4. 根据应用场景在HandlerThread的handleMessage中调用UI线程的Handler,更新UI。

下面我用一个简单的例子演示该调用方式。

创建HandlerThread的子类,复写构造方法,指定优先级和线程名;复写onLoopPrepared进行初始化的相关操作。创建一个sendMessage(Message msg)方法,可供外部调用,添加新的任务执行。

    /**
     * 用来下载文件的一个HandlerThread
     *
     * Created by rytong on 2018/2/3.
     */

    public class DownloadHanderThread extends HandlerThread implements Handler.Callback{

        private Handler downLoadHandler;

        private ArrayList<String> mDownLoadUrlList;

        private Handler UIHandler;

        public DownloadHanderThread(String name) {
            super("download Thread!");
        }

        public void setUIHandler(Handler UIHandler) {
            this.UIHandler = UIHandler;
        }

        public void setmDownLoadUrlList(ArrayList<String> mDownLoadUrlList) {
            this.mDownLoadUrlList = mDownLoadUrlList;
        }

        @Override
        protected void onLooperPrepared() {
            super.onLooperPrepared();
            downLoadHandler = new Handler(getLooper(),this);

            if (UIHandler == null){
                throw new IllegalArgumentException("UIHandler不能为空!!");
            }

            //将初始的下载队列,进行排队
            for (int i=0;i<mDownLoadUrlList.size();i++){
                String url = mDownLoadUrlList.get(i);
                Message message = Message.obtain();
                message.obj = url;
                downLoadHandler.sendMessage(message);
            }
        }
        /**
         * 执行新消息
         */
        public void sendMessage(Message msg){
            if (downLoadHandler == null){
                throw new IllegalArgumentException("downLoadHandler不能为空!");
            }
            downLoadHandler.sendMessage(msg);
        }

        @Override
        public boolean handleMessage(Message msg) {
            // 处理工作线程的异步任务(非UI线程)
            String url = (String) msg.obj;
            if (!TextUtils.isEmpty(url)){
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //给UI线程传递消息
                Message message = Message.obtain();
                message.obj = url;
                UIHandler.sendMessage(message);
            }
            return true;
        }
    }

在MainActivity中执行HandlerThread,并可以通过按钮事件添加新的任务到Thread中,排队执行

    public class MainActivity extends AppCompatActivity implements Handler.Callback, View.OnClickListener {

    private Button bt;
    private TextView tv;
    private DownloadHanderThread downloadHanderThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bt = (Button) findViewById(R.id.bt);
        tv = (TextView) findViewById(R.id.tv);
        // 创建HandlerThread
        downloadHanderThread = new DownloadHanderThread("");

        bt.setOnClickListener(this);

        ArrayList<String> urlList = new ArrayList<>();
        urlList.add("www.baidu.com/meinv.png");
        urlList.add("www.baidu.com/youxi.png");
        urlList.add("www.baidu.com/phone.png");

        Handler uiHandler = new Handler(Looper.getMainLooper(),this);

        // 初始化数据
        downloadHanderThread.setmDownLoadUrlList(urlList);
        downloadHanderThread.setUIHandler(uiHandler);
        downloadHanderThread.start();
    }



    @Override
    public boolean handleMessage(Message msg) {
        tv.append("\n"+(String)msg.obj+":下载完成");
        return true;
    }

    @Override
    public void onClick(View v) {
        String url = "老板又让我去下载美女图片,地址:www.baidu.com/meinv.png";
        Message message = Message.obtain();
        message.obj = url;
        downloadHanderThread.sendMessage(message);
    }
}

动态图演示:

这里写图片描述

3. HandlerThread的使用场景

  1. 可以使用在需要频繁调用子线程执行耗时任务的地方(比如,文件的下载等)
  2. 为了保证不让多线程影响业务逻辑,需要同步执行任务的场景,同时还不能阻塞UI线程(推送消息接收处理)

4. HandlerThread源码剖析

  1. HandlerThread是一个线程,重要逻辑在run方法中,Looper的获取加了同步逻辑。其他代码跟我们在子线程创建Looper一样。

        public void run() {
            mTid = Process.myTid();
            Looper.prepare();
            synchronized (this) {
                mLooper = Looper.myLooper();
                notifyAll();
            }
            Process.setThreadPriority(mPriority);
            onLooperPrepared();
            Looper.loop();
            mTid = -1;
        }
    
  2. 创建Looper时需要阻塞线程,只有等looper获取到之后才能继续执行。这是因为,我们调研getLooper是在run方法执行前,所以,需要保证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;
    }
    
  3. 退出

    有quit() 和quitSafely()两个方法,区别在于,直接退出还是执行完非延迟任务再退出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值