Android IntentService的使用与源码解析

尊重原创,转载请注明出处:http://blog.csdn.net/a740169405/article/details/50274537

前言:

   大家都知道,Service是Android中运行在后台的,不可见的服务。
   但其和异步线程又不一样,因为Service是运行在主线程,也就是UI线程里。所以我们并不能在Service中执行耗时的操作。
   为了解决这个问题,大家可能回在Service中开启一个线程,来执行耗时操作。
   谷歌为我们实现了类似的功能,那就是IntentService。

IntentService介绍:

  1. IntentService是继承了Service的抽象类,它是个服务,要使用它必须继承IntentService并实现抽象方法。
  2. IntentService可以执行后台耗时任务,当任务都执行完成后,IntentService会自动结束,不需要手动调用stopSelf();
  3. IntentService的优先级比线程高,因为是跑在后台的服务,所以不容易被系统杀死。
  4. IntentService内部是通过封装HandlerIntent来执行后台任务的,因为是通过消息队列接受Intent,所以后台任务是串行执行。

IntentService使用:

新建一个Activity与一个IntentService,从Activity中发送三个Intent,也就是启动执行startService三次,每次intent里的数据都不一样。

IntentServiceActivity:

public class IntentServiceActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = new Intent(this, MyIntentService.class);
        intent.putExtra(MyIntentService.EXTRA_KEY, "my task one #");
        // 发送任务1
        startService(intent);
        intent.putExtra(MyIntentService.EXTRA_KEY, "my task two #");
        // 发送任务2
        startService(intent);
        intent.putExtra(MyIntentService.EXTRA_KEY, "my task three #");
        // 发送任务3
        startService(intent);
    }
}

Activity中仅仅是向IntentService发送了三个消息

继承IntentService,并实现onHandleIntent方法。
MyIntentService:

public class MyIntentService extends IntentService {

    public static final String TAG = MyIntentService.class.getSimpleName();

    public static final String EXTRA_KEY = "task_name";

    public MyIntentService() {
        super(TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        String value = intent.getStringExtra(EXTRA_KEY);
        if (value.contains("two")) {
            try {
                // 如果是第二个任务,则sleep三秒。
                // 发现第三个任务仍然在第二个任务之后执行,说明任务是串行执行的
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Log.e(TAG, "thread : " + Thread.currentThread().getName() + "  " + value);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 服务结束时,打印Log
        Log.e(TAG, "onDestroy");
    }
}

在MyIntentService的onHandleIntent方法里,打印出了intent的key为task_name对应的值。
当收到含有”two”字符(这里我为了方便这样做的),线程Sleep三秒。在每次onHandleIntent被调用的时候,
打印出当前线程的名字。

看看Log信息:

chen.com.incubationcenter E/MyIntentService: thread : IntentService[MyIntentService] my task one #
chen.com.incubationcenter E/MyIntentService: thread : IntentService[MyIntentService] my task two #
chen.com.incubationcenter E/MyIntentService: thread : IntentService[MyIntentService] my task three #
chen.com.incubationcenter E/MyIntentService: onDestroy

我们会发现,处理任务的线程并不是主线程,并且即使第二个任务sleep了三秒,但是第三个任务还是在第二个任务完成后才执行,说明任务的处理是串行的。

IntentService源码解析:

下面我们分析三个问题:
1. IntentService是怎么实现异步线程执行任务的。
2. 为什么任务是串行执行的。
3. 每次startService并没有重新启动服务,并且,在所以任务完成后,服务自动终止。

带着问题分析源码:

IntentService内部是通过HandlerThread实现异步执行任务的。
想了解HandlerThread的相关知识的同学,可以查阅博客:HandlerThread源码解析
HandlerThread是一个内部维护了一个消息队列的线程。任务就是通过它来执行的。
我们找到IntentService类的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类并传入工作线程的名字
    HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
    // 开启后台线程
    thread.start();

    // 获取后台线程的Looper
    mServiceLooper = thread.getLooper();
    // 创建一个ServiceHandler对象,用来处理消息。
    mServiceHandler = new ServiceHandler(mServiceLooper);
}

在onCreate方法里,首先新建了一个HandlerThread对象,接着创建了一个叫ServiceHandler的类,
该类是IntentService的内部类,该类继承了Handler,构造函数传入了HandlerThread对象的Looper。
看看他的定义:

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

    @Override
    public void handleMessage(Message msg) {
        // 收到消息的时候,回调了onHandleIntent方法,并把Intent对象传递过去
        onHandleIntent((Intent)msg.obj);
        // 完成任务后,调用stopSelf方法,并传入消息的索引
        stopSelf(msg.arg1);
    }
}

我们发现,onHandleIntent方法就是在ServiceHandler收到消息后回调的。
也就是说onHandleIntent方法是在HandlerThread线程中执行的,这也就是疑惑一中为什么任务在异步线程中执行。

此外,因为任务是通过ServiceHandler发送给异步线程的消息队列的,而消息队列里的消息是依次取出并执行的,这也就是疑惑二中为什么任务是串行执行的。

最后,我们发现,onHandleIntent执行完成以后,IntentService并没有马上执行onstopSerlf方法,而是执行了其另一个带参数的方法。
该方法是定义在Service类下的。

/**
 * Old version of {@link #stopSelfResult} that doesn't return a result.
 *
 * @see #stopSelfResult
 */
public final void stopSelf(int startId) {
    if (mActivityManager == null) {
        return;
    }
    try {
        mActivityManager.stopServiceToken(
                new ComponentName(this, mClassName), mToken, startId);
    } catch (RemoteException ex) {
    }
}

该方法调用了ActivityManager的stopServiceToken方法来停止当前服务,关于ActivityManager这里不做介绍,有兴趣的朋友可以google相关资料。
既然调用了结束服务的方法,为什么服务没有马上结束,而是继续完成剩下的任务后才结束呢。
我们发现这里有个startId,没错就是因为他。startId是在Service类的onStart方法里被初始化的,
而onStart方法又是在onStartCommand方法里被调用的。
我们看看IntentService的源码:
onStartCommand:

   /**
     * 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(Intent intent, int flags, int startId) {
        // 直接调用onStart方法
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

onStart:

    @Override
    public void onStart(Intent intent, int startId) {
        // 构建了一个消息
        Message msg = mServiceHandler.obtainMessage();
        // 将startId作为参数传递
        msg.arg1 = startId;
        // 需要处理的
        msg.obj = intent;
        // 调用ServiceHandler发送消息
        mServiceHandler.sendMessage(msg);
    }

我们知道,每次调用startServcie方法启动一个服务,都会调用一次onStartCommand,每次也都会带一个startId过去,那么执行多个任务就有多个startId(关于这里不做介绍,大家可以理解为服务启动的顺序ID)
那么在onHandleIntent执行后调用的stopSelf方法确实告诉系统需要停止服务,但是系统会根据startId来判断是否所有的任务都已完成,如果是,则停止服务,如果不是,则等待所有的任务都完成后停止服务。到此,疑惑三搞定。

**

总结:

**
1. IntentService内部通过HandlerThread线程来执行异步任务,我们不需要自己创建线程
2. IntentService默认实现了onStartCommand以及onStart方法来讲intent传递给HandlerThread的消息队列
3. IntentService默认实现了onBind方法,并返回了空。
4. 无需手动调用stopSelf方法,所有任务都执行完成后,IntentService会自动结束服务。

感谢:
Android Service总结05 之IntentService
Android基本功:IntentService的使用
《Android开发艺术探秘》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值