IntentService使用详解 四大组件

Quibbler 2020-1-23 1443

IntentService使用详解


        之前已经学习过Android的四大组件之一Service,但是Service和前台运行在一个进程里,不能再Service中执行耗时操作,否则需要开启线程,执行完毕之后再借助Handler传回到主线程处理,Android提供了很多线程间通信的消息机制。

        Google又进一步进行了封装,提供了IntentService,内部对ServiceHandler进行了封装,做到用完即走,也不需要手动停止服务。更加方便,专注业务处理。IntentService的内部原理详见IntentService原理



1、IntentService

        IntentService类本身是一个抽象类,只有一个抽象方法onHandlerIntent(Intent intent),我们只需要继承IntentService,实现该方法,在该方法中执行耗时的任务即可。

     protected abstract void onHandleIntent(@Nullable Intent intent);


1.1、继承IntentService

        继承IntentService实现onHandlerIntent(Intent intent)方法。最好提供一个默认构造函数,调用父类构造函数。

    public class MyIntentService extends IntentService {
    
        public MyIntentService() {
            super("MyIntentService");
        }
        
        @Override
        protected void onHandleIntent(@Nullable Intent intent) {
            //耗时业务写在这里
        }
    }


1.2、onHandlerIntent(Intent intent)

        在onHandlerIntent(Intent intent)抽象方法中写后台逻辑,启动IntentService的时候,会自动启动该方法去执行。

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        //耗时业务写在这里
    }



2、注册IntentService

        别忘了自大组件都需要在AndroidManifest.xml中进行注册,否则无法使用。IntentService继承自Service也应当注册声明,否则无法启动IntentService。AndroidStudio对于未注册的IntentService也会提示:

    <service
        android:name=".MyIntentService"
        android:enabled="true"
        android:exported="false" />



3、启动IntentService

        启动IntentService很简单,而且启动后不用管执行完毕自动关闭。


3.1、startService

        和普通的Service一样直接通过startService()的方式启动

    Intent intent = new Intent(context, MyIntentService.class);
    context.startService(intent);

        注意:不要使用bind绑定的方式启动IntentService,否则IntentService就会和普通Service一样,失去IntentService的作用了。


3.2、多次启动IntentService

        多次启动 IntentService 不会重新创建新的服务和新的线程,只是把消息加入消息队列中等待执行。IntentService不能并行执行,只能一个一个按照先后顺序,当所有job完成的时候IntentService就销毁了,执行onDestroy回调方法。如果服务停止,会清除消息队列中的消息,后续的事件得不到执行。



4、IntentService源码

        IntentService的内部原理详见《IntentService原理》


4.1、方法执行流程

        先来打印一下IntentService各个方法的执行顺序。

        执行顺序:onCreate()->onStartCommand()->onStart()->onHandleIntent()


4.2、onHandlerIntent(Intent intent)

        查看onHandlerIntent(Intent intent)源码可以看到,内部调用了onStart()方法

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

        在继续看onStart()方法,这里给Handler发送了一个消息,而这个消息Message.obj携带的就是startService()的参数Intent

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

        而这个mServiceHandler定义如下:

    private volatile ServiceHandler mServiceHandler;

        mServiceHandler在IntentService的onCreate()方法中通过HandlerThread线程的Looper进行初始化。关于Looper详见《Handler、Looper、MessageQueue消息机制原理》

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

        内部类ServiceHandler继承自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的handlerMessage()中,收到onStart()发送的消息,开始在Looper所在的子线程HandlerThread中执行onHandleIntent(Intent)方法



不忘初心的阿甘
最新回复 (2)
  • Quibbler 2020-1-23
    2

    注意遇到的坑点

            继承IntentService实现自己的IntentService,一定要提供一个无参的默认构造函数

        public MyIntentService() {
            super("MyIntentService");
        }

            如果光有下面这个构造函数,不能正常启动startService,运行时会报错,需要提供零参数的构造函数:

        public MyIntentService(String name) {
            super(name);
        }



    • 安卓笔记本
      4
        登录 注册 QQ
返回
仅供学习交流,切勿用于商业用途。如有错误欢迎指出:fluent0418@gmail.com