HandlerThread、IntentService基本使用

一、HandlerThread实现异步通信

HandlerThread实际上就是使用了Thread+Handler进行封装而已,从使用的角度会比直接用Thread+Handler的形式更便捷。

1、子线程向主线程发送消息
final Handler mainHandler = new Handler(getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // 这里处理会在主线程
        EZLog.i("====handleMessage====" + Thread.currentThread().getName());
    }
};
new Thread(){
    @Override
    public void run() {
        mainHandler.sendEmptyMessage(0);
    }
}.start();
2、子线程向主线程发送消息
new Thread(){
    @Override
    public void run() {
        // 使用主线程的Looper
        MyHandler handler = new MyHandler(getMainLooper());
        // 相当于发送到主线程的那个Looper的消息队列里
        // 那个Looper.loop轮询早就在ActivityThread里就开启了
        handler.sendEmptyMessage(0);
    }
}.start();
static class MyHandler extends Handler {
    MyHandler(Looper looper) {
        super(looper);
    }
    @Override
    public void handleMessage(Message msg) {
        // 这里处理会在主线程进行
        EZLog.i("====handleMessage====" + Thread.currentThread().getName());
    }
}
3、子线程向子线程发送消息
new Thread(){
    @Override
    public void run() {
        // 关于子线程创建Handler需要Looper.prepare和Looper.loop在
        // Handler的消息处理机制那一节已经讲过
        Looper.prepare();
        MyHandler handler = new MyHandler();
        handler.sendEmptyMessage(0);
        Looper.loop();
    }
}.start();
static class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        // 这里处理会在子线程进行
        EZLog.i("====handleMessage====" + Thread.currentThread().getName());
    }
}

那么问题来了,Handler的handleMessage所执行的线程是由什么来决定的?
从以上三种情况来看,好像和handler创建所处的线程无关,情况一是在主线程中创建的,情况二是在子线程中创建的。
没错,答案是Looper创建时所处的线程,并不是Handler创建时所处的线程。
当我们在创建Handler的时候,如果不传入Looper,就会去获取当前线程的ThreadLocalMap里保存的Looper对象(在Looper.prepare的时候创建并保存的),如果传入Looper,则使用传入的Looper。每个Looper内部都对应一个MessageQueue,当我们调用handler.sendMessage的时候,实际上就是把消息发送到对应Looper的MessageQueue里。Looper.loop方法会轮询这个MessageQueue,如果是主线程的Looper,其loop方法必然是执行在主线程,因而其handler回调也必然是执行在主线程。

4、HandlerThread的使用(相当于3的简化版)
HandlerThread thread = new HandlerThread("Thread Name");
thread.start();

Handler handler = new Handler(thread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // 这里会在HandlerThread创建的这个线程里执行
        EZLog.i("====handleMessage====" + Thread.currentThread().getName());
    }
};
handler.sendEmptyMessage(0);

HandlerThread实际上是一个Thread的子类,当我们调用thread.start()的时候,会执行线程的run方法,我们看看HandlerThread的run方法做了什么

/**
* HandlerThread的run方法
*/
@Override
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。创建一个Handler,这个Handler用到的Looper是thread.getLooper,也就是这个HandlerThread线程里prepare所创建的Looper。因此handlerMessage所执行的线程即为线程HandlerThread。

二、IntentService

IntentService,可以看做是Service和HandlerThread的结合体,在完成了使命之后会自动停止,适合需要在工作线程处理UI无关任务的场景。
我们知道,Service不是一条新的线程,因此不应该在Service中直接处理耗时的任务,否则很容易出现ANR(Application Not Responding)的情况。
如果在Service中要做一些耗时的行为,比如下载文件等,那么就需要在Service中单独开一个Thread来进行这些操作,而我们知道,线程开启后,那么这个Service已经不存在或者停止了,线程依然不好控制其状态。因此Android引进了IntentService:
(1)IntentService是一个抽象类,继承于Service,因此它本质还是一个服务
(2)IntentService内部封装了HandlerThread+Handler来实现异步通信操作
(3)当执行完任务后,也就是onHandleIntent执行完毕后,服务会自动停止
(4)如果启动IntentService多次,那么每一个耗时操作会以工作队列的方式在 IntentService 的 onHandleIntent 回调方法中执行,依次去执行,使用串行的方式,执行完自动结束。

1、使用
public class DownloadService extends IntentService {

    public DownloadService(String name) {
        super(name);
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    }

    // onHandleIntent中处理耗时的操作,比如文件下载
    @Override
    protected void onHandleIntent(Intent intent) {
        try {
            Thread.sleep(1000);
            int count = 0;
            while (count < 100) {
                count++;
                Thread.sleep(50);
            }
        } catch (InterruptedException e) {
        }
    }

    @Override
    public void onDestroy() {
    }
}
2、IntentService源码
@Override
public void onCreate() {
    // TODO: It would be nice to have an option to hold a partial wakelock
    // during processing, and to have a static startService(Context, Intent)
    // method that would launch the service & hand off a wakelock.

    super.onCreate();
    // 初始化HandlerThread并开启
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();
    // 关联Looper
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
}

@Override
public void onStart(@Nullable Intent intent, int startId) {
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    // 发送消息
    mServiceHandler.sendMessage(msg);
}

// Handler
private final class ServiceHandler extends Handler {
    public ServiceHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        // 处理消息,调用我们重写的onHandleIntent方法
        onHandleIntent((Intent)msg.obj);
        // 关闭服务
        stopSelf(msg.arg1);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值