为了账号安全,请及时绑定邮箱和手机立即绑定

异步处理老司机:IntentService 源码分析

标签:
源码

IntentService 介绍

IntentService 是一种特殊的 Service,它继承了 Service 并且它是一个抽象类,因此必须创建它的子类才能够使用 IntentService。它可用于执行后台耗时任务,当任务执行完成后它会自动停止,在资源不足时,系统会对一些被认为时无用的资源给清理掉,由于它是 Service 的原因,它的优先级比单纯的线程的优先级高很多,不容易被系统杀死(清理掉),所以它适合执行一些高优先级的后台任务。在实现上,IntentService 封装了 Handlerhread 和 Handler。

HandlerThread 继承了 Thread,它是一种可以使用 Handler 的 Thread。它的实现是通过在run()方法中通过Looper.prepare()来创建消息队列,并通过Looper.loop()方法来开启消息循环, 它的内部对Thread 的 run 方法进行重写,通过Handler的消息方式(Looper循环)来通知HandlerThread执行一个具体的任务。

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

在明确了不需要使用HandlerThread的时,可以通过它的quit或者quitSafely方法来终止线程的执行

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;
}

这两个方法的区别是:

quit()
使用此方法可能是不安全的,因为在Looper队列终止之前可能无法传递某些消息。

quitSafely()
使用此方法可能是安全的,因为一旦已经传递消息,队列中的所有剩余消息被处理,方法就会终止。然而,在循环终止之前,延迟的消息将在未来的到期时间内不传递。

从源码来分析 IntentService 的执行顺序

在onCreate()初始化HandlerThread和ServiceHandler,用于在后面调用onStart后来发送消息。

@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 thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();

    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
}

每次启动服务都会调用一次onStartCommand()方法,并且它会调用onStart()

@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
    onStart(intent, startId);
    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

在onStart()中发送消息

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

后台任务是顺序执行的
因为 Handler 中的 Looper 是顺序处理消息。

任务执行完成之后结束服务:

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

    @Override
    public void handleMessage(Message msg) {
        onHandleIntent((Intent)msg.obj);
        // 使用 stopSelf(msg.arg1); 而不使用 stopSelf();
        // 是因为 stopSelf() 会立即停止服务,
        // 而 stopSelf(msg.arg1); 在停止服务前会先判断最近启动服务的次数是否和 startId 相等
        // 如果相等就历经停止服务,不想动则不停止服务
        stopSelf(msg.arg1);
    }
}

IntentService 使用

创建一个实例继承自 IntentService

public class TestIntentService extends IntentService {
    private static final String TAG = "TestIntentService";

    public TestIntentService() {
        super(TAG);
        Log.e(TAG, "TestIntentService: " );
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate: " );
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        String taskAction = intent.getStringExtra("task_action");
        SystemClock.sleep(3000);
        Log.e(TAG, "onHandleIntent: "+taskAction);
    }

    @Override
    public void onDestroy() {
        Log.e(TAG, "onDestroy: service destory" );
        super.onDestroy();
    }
}

注册服务
在AndroidMainfest.xml中注册服务

<service android:name=".thread.TestIntentService"/>

开启服务

Intent intent = new Intent(CallBackTestActivity.this, TestIntentService.class);
intent.putExtra("task_action","com.dx.action.TASK1");
// 开启第一个服务
startService(intent);
intent.putExtra("task_action","com.dx.action.TASK2");
// 开启第二个服务
startService(intent);
intent.putExtra("task_action","com.dx.action.TASK3");
// 开启第三个服务
startService(intent);

输出结果是:

从截图中的时间,以及输出顺序正好验证了上面的叙述!ok,完工~

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消