美文网首页Android开发Android开发经验谈
017 Android多线程-IntentService-源码解

017 Android多线程-IntentService-源码解

作者: 凤邪摩羯 | 来源:发表于2021-01-10 09:38 被阅读0次

目录

image

1. 定义

Android里的一个封装类,继承四大组件之一的Service


2. 作用

处理异步请求 & 实现多线程


3. 使用场景

线程任务 需 按顺序在后台执行

  1. 最常见的场景:离线下载
  2. 不符合多个数据同时请求的场景:所有的任务都在同一个Thread looper里执行

4. 工作原理

4.1 流程示意图

  • IntentService的工作原理 & 源码工作流程如下:
image

4.2 特别注意

若启动IntentService 多次,那么 每个耗时操作 则 以队列的方式IntentServiceonHandleIntent回调方法中依次执行,执行完自动结束

接下来,我们将通过 源码分析 解决以下问题:

  • IntentService 如何单独开启1个新的工作线程
  • IntentService 如何通过onStartCommand() 将Intent 传递给服务 & 依次插入到工作队列中

5. 源码分析

问题1:IntentService如何单独开启1个新的工作线程

主要分析内容 = IntentService源码中的 onCreate()方法

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

    // 1\. 通过实例化andlerThread新建线程 & 启动;故 使用IntentService时,不需额外新建线程
    // HandlerThread继承自Thread,内部封装了 Looper
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    thread.start();

    // 2\. 获得工作线程的 Looper & 维护自己的工作队列
    mServiceLooper = thread.getLooper();

    // 3\. 新建mServiceHandler & 绑定上述获得Looper
    // 新建的Handler 属于工作线程 ->>分析1
    mServiceHandler = new ServiceHandler(mServiceLooper); 
}

   /** 
     * 分析1:ServiceHandler源码分析
     **/ 
     private final class ServiceHandler extends Handler {

         // 构造函数
         public ServiceHandler(Looper looper) {
         super(looper);
       }

        // IntentService的handleMessage()把接收的消息交给onHandleIntent()处理
        @Override
         public void handleMessage(Message msg) {

          // onHandleIntent 方法在工作线程中执行
          // onHandleIntent() = 抽象方法,使用时需重写 ->>分析2
          onHandleIntent((Intent)msg.obj);
          // 执行完调用 stopSelf() 结束服务
          stopSelf(msg.arg1);

    }
}

   /** 
     * 分析2: onHandleIntent()源码分析
     * onHandleIntent() = 抽象方法,使用时需重写
     **/ 
      @WorkerThread
      protected abstract void onHandleIntent(Intent intent);

问题2:IntentService 如何通过onStartCommand() 将Intent 传递给服务 & 依次插入到工作队列中


/** 
  * onStartCommand()源码分析
  * onHandleIntent() = 抽象方法,使用时需重写
  **/ 
  public int onStartCommand(Intent intent, int flags, int startId) {

    // 调用onStart()->>分析1
    onStart(intent, startId);
    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

/** 
  * 分析1:onStart(intent, startId)
  **/ 
  public void onStart(Intent intent, int startId) {

    // 1\. 获得ServiceHandler消息的引用
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;

    // 2\. 把 Intent参数 包装到 message 的 obj 发送消息中,
    //这里的Intent  = 启动服务时startService(Intent) 里传入的 Intent
    msg.obj = intent;

    // 3\. 发送消息,即 添加到消息队列里
    mServiceHandler.sendMessage(msg);
}

至此,关于IntentService的源码分析讲解完毕。


6. 源码总结

从上面源码可看出:IntentService本质 = Handler + HandlerThread

  1. 通过HandlerThread 单独开启1个工作线程:IntentService
  2. 创建1个内部 HandlerServiceHandler
  3. 绑定 ServiceHandlerIntentService
  4. 通过 onStartCommand() 传递服务intentServiceHandler 、依次插入Intent到工作队列中 & 逐个发送给 onHandleIntent()
  5. 通过onHandleIntent() 依次处理所有Intent对象所对应的任务

因此我们通过复写onHandleIntent() & 在里面 根据Intent的不同进行不同线程操作 即可


7. 注意事项

此处,有两个注意事项需要关注的:

  1. 工作任务队列 = 顺序执行
  2. 不建议通过 bindService() 启动 IntentService

注意事项1:工作任务队列 = 顺序执行

即 若一个任务正在IntentService中执行,此时你再发送1个新的任务请求,这个新的任务会一直等待直到前面一个任务执行完毕后才开始执行

  • 原因:
  1. 由于onCreate()只会调用一次 = 只会创建1个工作线程;
  2. 当多次调用 startService(Intent)时(即 onStartCommand()也会调用多次),其实不会创建新的工作线程,只是把消息加入消息队列中 & 等待执行。
  3. 所以,多次启动 IntentService 会按顺序执行事件

若服务停止,则会清除消息队列中的消息,后续的事件不执行

注意事项2:不建议通过 bindService() 启动 IntentService

原因:

// 在IntentService中,onBind()`默认返回null
@Override
public IBinder onBind(Intent intent) {
    return null;
}

  • 采用 bindService()启动 IntentService的生命周期如下:

onCreate() ->> onBind() ->> onunbind()->> onDestory()

  • 即,并不会调用onStart()onStartcommand()故不会将消息发送到消息队列,那么onHandleIntent()将不会回调,即无法实现多线程的操作

此时,你应该使用Service,而不是IntentService


8. 对比

此处主要讲解IntentService与四大组件Service、普通线程的区别。

8.1 与Service的区别

image

8.2 与其他线程的区别

image

相关文章

网友评论

    本文标题:017 Android多线程-IntentService-源码解

    本文链接:https://www.haomeiwen.com/subject/btffoktx.html