IntentService使用详解

QuibblerQuibbler 2020-01-23 约 10 分钟 1873 次阅读

IntentService使用详解

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

Google又进一步进行了封装,提供了IntentService,内部对Service和Handler进行了封装,做到用完即走,也不需要手动停止服务。更加方便,专注业务处理。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)方法

相关推荐

精选
ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager
Android

ViewPager和PagerAdapter、FragmentPagerAdapter、FragmentStatePager

ViewPager1、ViewPagerandroidx.viewpager.widget.ViewPager,Android中使用非常广泛的控件,可以说是APP必备:首次打开引导页、页面Banner广告等。常用方法:setAdapter() 设置适配器setOffscreenPageLimit() 设置缓存的页面个数,默认是 1setCurrentItem() 跳转到特定的页面setOnPage

1.1k
获取Android内置WebView内核版本
Android

获取Android内置WebView内核版本

获取Android内置WebView内核版本竟然能遇到这样奇葩的事情,网页用的技术过于新颖,以至于只支持高版本Chromium内核的,低版本安卓系统中内置的内核版本较低,无法加载前端页面。1、设置查看在系统设置里 > 应用 > 应用管理 > 显示系统应用,查看WebView组件:2、页面查看通过WebView发起的网络请求,都会带上浏览器的UA,通常页面都可以通过UA判断浏览器的内核版本。这里有两

1.1w
Android 14适配总结
Android

Android 14适配总结

Android 14适配总结毕业工作至今已经适配了三个Android大版本,从Android 11到Android 12、再到Android 13。2023年,Google即将推出的Android 14,上半年已经开始第一批适配。现在,第四个Android版本已经适配完,总结记录一下。1、Android 14计划Google一般会在2月份对外发布预告,同时放出开发者预览版。“拉通”各大平台、厂商以

1.1w

评论 (1)

评论功能已关闭,仅展示历史评论
Quibbler
Quibbler

注意遇到的坑点

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

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

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

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