继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

IntentService详解

晨雨细曲
关注TA
已关注
手记 13
粉丝 3
获赞 41

图片描述

IntentService

Service执行任务的时候,并不是在子线程中执行,而是在主线程中执行,所以我们在Service中不能执行一些耗时操作,避免造成ANR现象。如果非要进行网络请求等耗时操作的话,这里可以使用两种方式进行处理。

1.在Service中开启一个子线程,在子线程中进行耗时操作。

但是这里需要声明一个事情,可能有人会问,为什么不能在别的组件中开启子线程进行耗时操作?由于Activity可能会被用户退出,而Broadcast本来生命周期就短。当Activity被用户点击退出之后,子线程这时执行耗时操作的任务还没有完成。在Activity退出的时候,他们的进程就变成了空进程,系统需要内存的时候可能会优先结束掉该进程,如果宿主进程结束了,那么这个进程中的所有子线程也会结束掉,导致任务在子线程中无法执行完成。

2.使用IntentService来处理。

IntentService是Service的子类。里面专门开辟了一个子线程来进行耗时操作。当任务结束之后,会自动停止,所以不用我们去调用stopService来停止他。

IntentService默认为Service提供了onBind()和onStartCommand()方法,所以我们在继承使用IntentService的时候不用再重写这两个方法,而直接使用onHandleIntent(Intent intent)方法即可。

IntentService有以下几个特点:

  • 默认在子线程中处理回传到onStartCommand()方法中的Intent;

  • 在重写的onHandleIntent()方法中处理按时间排序的Intent队列,所以不用担心多线程(multi-threading)带来的问题。

  • 所有请求处理完成后,自动停止service,无需手动调用stopSelf()方法;

  • 默认实现了onBind()方法,并返回null;

  • 默认实现了onStartCommand()方法,并将回传的Intent以序列的形式发送给onHandleIntent(),您只需重写该方法并处理Intent即可。

onHandleIntent(Intent intent): 此方法专门开辟了一个子线程来进行耗时操作的处理。并且这个调用耗时操作的方式是以队列的形式进行调用,也就是说如果有多个耗时操作进行处理的时候,他会排队进行操作。

如果您还希望在IntentService的 继承类中重写其他生命周期方法,如onCreate()、onStartCommand() 或 onDestroy(),那么请先调用各自的父类方法以保证子线程能够正常启动。

比如,要实现onStartCommand()方法,需返回其父类方法:


 @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e(TAG,"onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

源码分析

在学习的时候,我们除了知其然,还要知其所以然,所以我们除了会使用IntentService之外,还需要对IntentService的源码进行一波分析,来知道他内部的实现原理。

由于IntentService是Service的子类,所以IntentService必然继承了Service,并且实现了Service的onCreate()、onBind()、onStartCommand()、onDestroy()这几个主要的方法。我们逐一来查看这几个方法。

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

通过源码我们可以看到,在第一次启动IntenService的时候,会去执行onCreate()方法。在onCreate()方法中,程序先去创建了一个HandlerThread线程并且启动了他,然后实现一个继承了Handler的ServiceHandler类,并将HandlerThread的Looper传递给ServiceHandler,由于Looper属于HandlerThread,HadlerThrad又是一个异步线程,当我们把Looper传递给ServicerHandler时,使得ServiceHandler也变成了一个异步执行的线程。

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

之后程序去执行onStartCommand()方法,在这个方法里面调用了onStart()方法,在onStart()方法里面,通过ServiceHandler对象发送了一个handler的Message去启动这个异步线程。这样也就满足了我们在编写代码的时候应该注意的一点,在onCreate()中进行一些初始化操作,而在onStartCommand()执行一些具体的操作。

我们再来看ServiceHandler的内部代码


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

可以发现在handlerMessage中我们执行了IntentService里面执行耗时操作的方法onHandleIntent(),由于是在一个子线程中执行的,这也就解释了为何onHandleIntent()方法里面可以进行耗时操作的原因,因为他本身就是在一个子线程中执行。

在执行完成onHandleIntent()方法之后,程序调用了stopSelf()方法来结束Service。这里必须说明下为什么使用stopSelf(int start)而不是用stopSelf()来停止

stopSelf(): 会立马结束服务

stopSelf(int startId): 等待所有消息都处理完后才终止服务

IntentService本身就是一个以队列的形式来处理异步操作的类,所以使用stopSelf(int startId)是为了让队列中的所有耗时操作全都执行结束之后再结束整个Service。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP