IntentService全面分析讲解

一、简介

我们在《HandlerThread全面分析讲解》中全面分析了HandlerThread的原理和应用,而IntentService中核心元素就是HandlerThread,也可以说是HandlerThread的另一种使用场景。
本质:IntentService的本质是Service服务。前面我们在《关于Service服务常用的知识》中也讲到了,Service服务运行在主线程,如果有耗时操作的话,需要在服务中创建子线程,而HandlerThread本质又是线程,因此IntentService算是Thread和Service的结合使用场景。IntentService本身是抽象类,因此算是在普通Service的基础上加了一个就有消息机制的子线程并对相关功能进行了封装。
特质:当所有任务完成后,IntentService会自动停止。
拥有较高的优先级,不易被系统杀死,因此比较适合执行一些高优先级的异步任务。
使用方式简单,创建IntentService子类,实现onHandlerIntent方法和构造方法,onHandlerIntent为异步方法,可以执行耗时操作。

二、跟踪源码,分析IntentService的工作原理
1、创建子类时,要重写的方法
public class CustomIntentService extends IntentService {
    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public CustomIntentService(String name) {
        super(name);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // 处理耗时操作
    }
}
2、IntentService的本质是普通Service,因此和Service服务的特质是一样的,跟踪onCreate()方法
@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);
}
  • onCreate()方法是服务第一次被创建的时候调用
  • 关键一:创建一个HanlerThread,我们知道HandlerThread本质是Thread,是一个拥有Looper的Thread,是一个拥有消息机制必备元素的子线程。
  • 关键二:获取拥有Looper元素的线程的Looper对象。
  • 关键三:外部创建Handler元素,与HandlerThread的Looper对象进行绑定,组成一个完整的消息机制。
3、Handler处理消息
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);
    }
}
  • 关键一:Handler绑定的是子线程的Looper,因此Handler的dispatchMessage()方法会在子线程中调用,所以handleMessage()方法中的工作都是在子线程中完成的。
  • 关键二:最终使用者只需实现onHandlerIntent()方法即可。
  • 关键三:onHandleIntent中的工作完后,会自动关闭服务。
4、启动服务
@Override
public void onStart(@Nullable Intent intent, int startId) {
    // 关键一
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg);
}

/**
 * You should not override this method for your IntentService. Instead,
 * override {@link #onHandleIntent}, which the system calls when the IntentService
 * receives a start request.
 * @see android.app.Service#onStartCommand
 */
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
    onStart(intent, startId);
    return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
  • 通过与线程绑定的Handler将Message发送到子线程的队列中。
    从子线程的队列中取出消息最后处理消息,就回到了上一步的handleMessage方法中。
5、整个消息机制理解起来还是很抽象的,有一个很关键的点一定要理解记住,那就是Looper.java文件中的loop()方法
/**
 * Run the message queue in this thread. Be sure to call
 * {@link #quit()} to end the loop.
 */
public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    
    final MessageQueue queue = me.mQueue;
    for (;;) {
        // MessageQueue类的读取方法
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        try {
            // 取出数据后,交由发送者(Handler)处理消息
            msg.target.dispatchMessage(msg);
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        
        msg.recycleUnchecked();
    }
}
  • 整个精简后的代码逻辑就是获取到当前线程持有的Looper对象,获取到Looper对象所持有的消息队列MessageQueue,然后从消息队列中一个一个的取出消息(调用next()方法),从取出的消息中获取保存的Handler对象(即这条Message的发送者),调用Handler的dispatchMessage()方法,将消息交由Handler去处理。 msg.target.dispatchMessage(msg);这句话可是在工作线程中调用的,因此Handler的handleMessage()方法中的代码运行在工作线程。

6、最后看看使用者需调用的方法

/**
 * This method is invoked on the worker thread with a request to process.
 * Only one Intent is processed at a time, but the processing happens on a
 * worker thread that runs independently from other application logic.
 * So, if this code takes a long time, it will hold up other requests to
 * the same IntentService, but it will not hold up anything else.
 * When all requests have been handled, the IntentService stops itself,
 * so you should not call {@link #stopSelf}.
 *
 * @param intent The value passed to {@link
 *               android.content.Context#startService(Intent)}.
 *               This may be null if the service is being restarted after
 *               its process has gone away; see
 *               {@link android.app.Service#onStartCommand}
 *               for details.
 */
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
  • 关键一:This method is invoked on the worker thread with a request to process. 正如我们上面所讲,该方法在工作线程上调用。
  • 关键二:每次只能处理一个Intent,因此使用IntentService处理异步任务只能是串联执行无法并联执行。
  • 关键三:因为是串联执行,所有如果有一个Intent耗时比较久,会影响后面的Intent的执行时间。
  • 关键四:所有Intent执行完毕之后会自动执行stopSelf()方法,无需手动调用。
三、总结

关于IntentService的原理和简单的使用都讲完了。其实无论是HandlerThread还是IntentService都是官方帮我们封装的工具类,因为一些功能我们经常会用到,因此才有了这些官方工具类,省去了我们自己手动封装。正因为我们会遇到跨线程进行通信,工作线程有时候需要持有Looper创建自己的消息机制,因此有了HandlerThread。正因为Service服务运行在主线程,无法运行耗时任务,需在服务中创建子线程,因此利用HandlerThread的特性封装出了IntentService。但是这些工具类都有自己的特性,在使用前一定要分析好自己的需求特性是否和这些工具类特性相匹配。比如,IntentService只能是串联执行,如果想在服务中同时运行多个工作线程,那还是需要在服务中手动创建线程池,开启多个工作线程,同时并行多个任务。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值