Android HandlerThread源码解析

  • 前言

如果我们要执行多个耗时任务,第一时间想到的肯定是创建多个线程来执行任务,如果学过线程池那我们也可以使用线程池,那有没有比线程池更轻量级的呢?Handler了解一下~

纳尼! Handler也可以执行耗时任务吗? 那么问题就来了

  • 子线程怎么使用Handler?

先来试试能不能用

new Thread(new Runnable() {
    @Override
    public void run() {
        Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.d("lkx", String.valueOf(msg));
            }
        };
        Message message = Message.obtain();
        message.obj = "Hello";
        handler.sendMessage(message);
    }
}).start();

执行结果:
E/AndroidRuntime: FATAL EXCEPTION: Thread-2
    Process: com.example.hello, PID: 12612
    java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare()
        at android.os.Handler.<init>(Handler.java:227)
        at android.os.Handler.<init>(Handler.java:129)
        at com.example.hello.HandlerThreadActivity$2$1.<init>(HandlerThreadActivity.java:42)
        at com.example.hello.HandlerThreadActivity$2.run(HandlerThreadActivity.java:42)
        at java.lang.Thread.run(Thread.java:923)

果然…报错了,在报错信息中有一个特别眼熟的方法 Looper.prepare()

学完上一篇的Handler源码浅析,我们应该已经对Handler的流程很熟悉了,我们知道主线程之所以可以直接使用Handler,是因为APP启动的时候已经在ActivityThread.main()中初始化了Looper对象,那我们能不能在子线程中自己初始化呢?

new Thread(new Runnable() {
    @Override
    public void run() {
        Looper.prepare(); //初始化当前线程Looper对象
        Looper looper = Looper.myLooper(); //获取当前线程的Looper对象
        Handler handler = new Handler(looper) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Log.d("lkx", (String) msg.obj);
            }
        };
        Message message = Message.obtain();
        message.obj = "Hello";
        handler.sendMessage(message);
        Looper.loop(); //注意: Looper.loop内部是死循环,会阻塞导致后续代码无法执行
    }
}).start();

执行结果: Hello   Thread-2

上面代码我们看到Handler可以在子线程中使用,并且handlerMessage会在子线程中进行回调,也就是我们可以在handlerMessage中进行耗时操作了。

那每次这样写也太麻烦了,有没有更简单的方法呢? 当然有!Android早已经给我们提供好了类,没错就是HandlerThread~

  • HandlerThread怎么使用?

//创建一个HandlerThread并调用start()方法
HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();

//创建一个Handler,并传入HandlerThread的Looper对象
Handler handler = new Handler(handlerThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        Log.d("lkx", (String) msg.obj);
    }
};

//创建5个下载任务
for (int i = 0; i < 5; i++) {
    Message message = Message.obtain();
    message.obj = "下载任务" + i;
    handler.sendMessage(message);
}

执行结果:
	下载任务0
	下载任务1
	下载任务2
    下载任务3
    下载任务4
  • HandlerThread源码解析

从第一眼来看,HandlerThread继承Thread,也就是说HandlerThread应该是个线程

public class HandlerThread extends Thread {}
  • 构造方法

name: 线程名
priority: 线程优先级

public HandlerThread(String name) {
    super(name);
    mPriority = Process.THREAD_PRIORITY_DEFAULT;
}

public HandlerThread(String name, int priority) {
    super(name);
    mPriority = priority;
}
  • HandlerThread#run

既然是个线程,那执行的入口应该是run()方法
run()方法跟我们上面自定义的子线程使用Handler好像很相似,先调用Looper.prepare()初始化,然后调用Looper.loop()开启循环

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}
  • HandlerThread#getLooper

getLooper()这里非常设计的非常巧妙,为了保证可以正常拿到Looper对象,如果Looper对象为空会调用wait()释放锁进入等待状态,同时等待run()方法初始化,当run()方法拿到Looper对象后会调用notifyAll()方法通知,然后这里的wait()会被唤醒,代码继续往下走,直到返回Looper对象。

public Looper getLooper() {
    if (!isAlive()) {
        return null;
    }
    
    synchronized (this) {
        while (isAlive() && mLooper == null) {
            try {
                wait();
            } catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}
  • HandlerThread#quit

当不使用的时候,我们需要关闭Looper的循环,这个时候我们可以调用HandlerThread.quit()或者HandlerThread.quitSafely()停止循环,这两个的区别就是前者直接停止,后者是等任务执行完在停止。

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mHandlerThread!=null) {
        mHandlerThread.quit();
    }
}
  • 总结

HandlerThread本质上就是一个Thread,只不过内部已经帮我们开启了一个Looper循环,我们可以多次通过Handler发消息到MessageQueue中,Handler会通过Looper的循环器将消息传递到handleMessage中,这个循环器将会始终开启着,所以我们不使用的时候一定要及时关闭。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值