IntentService学习笔记

Service作为Android的四大主件之一,所以其重要性也是非同一般的。

由于我们不能再activity中处理时间过长的任务,因为这样会出现ARN,所以我们就需要将一些耗时任务放置到可以在后台运行并且不会影响前台Activity的响应的Service中。但是默认的Service是跑在主线程的。这样依旧会对主线程的响应产生一定的影响,所以我们可以使用IntentService,或者是使用Service加Thread等来实现。

那么我们为什么不直接使用Thread而是需要将其包装在Service中呢?
因为单单的Thread的系统优先级很低,当系统资源不足的时候就会被杀掉。而service的系统优先级是比较高的,只有当资源少到不足以维持前台activity的运行的时候才会将其杀死。所以为了保证一些重要的线程不被杀掉,我们就需要使用service。

另外系统为我们提供了好多的Service服务,我们可以通过getSystemService获得到这些服务。所以了解Service对于android开发是很重要的。

在了解IntentService之前我们需要先来了解一下Service的生命周期,毕竟IntentService也是继承于Service。




一、Service的生命周期:




下面我们就来了解一下Service的生命周期。左边的是在没有绑定情况下的生命周期,右边的在绑定情况下的生命周期


下面我做了一些测试来验证这个生命周期。



1、没有绑定情况下。



在下面的测试图中我调用了4次 startService和一次 stopService。结果Logcat中显示出来的方法调用如下。


从上面我们可以看出,当我第一次调用startService的时候就会执行 onCreateonStartCommand,但是后面我再调用startService的时候却就只调用 onStartCommand而已。直到我调用一次stopService的时候才会回调 onDestory
所以从上面中我们可以知道我们可以将自己需要处理的逻辑放置在onStartCommand方法中。然后调用startService开启一次任务。



2、在绑定的情况下。



在下面的测试图中我调用了4次 bindService和一次 unbindService


从图中我们可以看出,当我第一次调用bindService的时候会回调 onCreateonBind方法,但是后面不管我调用都少次bindService都不会再回调 onCreate或者 onBind方法。直到我调用unbindService的时候才会回调 onUnbindonDestory

需要注意的一点是:如果我还没有绑定service的时候调用unbindService的时候会出现异常,而如果我没有startService的话调用stopService并不会产生异常。



3、startService和bindService混合使用情况。



那么假如我又startService,又bindService呢?
下面测试调用顺序 startService --> bindService --> stopService --> unBindService


下面测试调用顺序startService --> bindService --> unbindService --> stopService


下面测试调用顺序bindService --> startService --> unbindService --> stopService


下面测试调用顺序bindService --> startService --> stopService --> unbindService


从上面四个测试可以得出一些规律:
a、bindService和startService不管哪个先调用都会先回调 onStart
b、调用unbindService的时候 onUnbind会被调用,而对于 onDestory来说必须调用完stopService和unbindService才会回调。

好了上面就大概说完了Service的基本的一些方法回调。
接下来我们进入今天的主角IntentService。



二、IntentService简述



我们都知道我们可以使用IntentService,并且重写其 onHandleIntent方法,而onHandleIntent方法会执行在另一个线程中,这样我们就可以不用自己在Service中添加一个线程了。 但是实际上IntentService也是和一个线程进行绑定的。然后通过一个Handler将我们的任务挂载到子线程的消息队列中去。

IntentService的生命周期:


因为IntentService是Service的子类。所以回调的生命周期也差不多。
在这个测试中我调用了 startService,可见其执行完了 onHandleIntent的时候就直接回调 onDestory了。


而对于bindServiceunbindService来说则回调差不多。



三、IntentService实现原理



好了接下来我们就来了解一下IntentService是如何工作起来的吧。
首先我们来借助一个图来解释一下


主要有两个步奏:

a、首先IntentService在onCreate方法中创建了一个 HandlerThread,然后HandlerThread又在其run方法中创建了一个 Looper。然后 IntentServcide通过这个子线程对象获得其Looper,然后又交给了 ServiceHandler

b、然后在有事务需要处理的时候 ServiceHandler就会将事务插入到HandlerThread的MessageQueue中,而HandlerThread的处理方法会直接回调 onhandleIntent

接下来我们来对这源码来看一下:

1、HandlerThread


首先我们先来了解一下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继承于Thread,它只是在run接口中创建了一个Looper并且让其跑起来。除此之外并没有什么特别的事。

2、ServiceHandler



接下来我们还要了解一下ServiceHander.
这个是IntentService的一个内部类:
    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);
        }
    }
其中在构造方法中传递了一个Looper对象。而这个Looper对象就是上面的HandlerThread在run方法中创建的 Looper对象。 然后如果Handler收到消息的话就会直接调用onHandleIntent方法来处理,如果处理完的话就会调用stopSelf方法来停止服务。

3、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 thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
我们从它的onCreate方法中可以看出
a、首先其new了一个 HandlerThread,并且开启了这个Thread。
b、得到这个thread的 Looper对象,并将其作为参数传递到 ServiceHandler的构造方法中,生成一个用来操作这个Looper的ServiceHandler对象。

在这里我们可能会有疑问,我现在开启了一个子线程后就立马调用thread. getLooper方法,这个时候可能Looper还没有被创建出来呢?
所以我们也来瞧一瞧其中的实现:
     public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
原来如果这个方法得到的mLooper为null的话就会一直等待下去,也就是说这个方法是阻塞的。

接着我们来看一下onCommandStart
    public int onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
可以看出其中又调用了onStart方法。
    @Override
    public void onStart(Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }
这个onStart印证了我们上面的推论。

c、在onStartCommand方法中将需要处理的任务包装成为一个Message然后交给了 ServiceHandler,ServiceHandler又将这个Message挂载到 HandlerThread的MessageQueue中去。

d、然后等待 HandlerThread处理消息的时候调用 onHandleIntent方法。

这样子整个思路大体就清楚了。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值