IntentService是什么

在内部封装了 Handler、消息队列的一个Service子类,适合在后台执行一系列串行依次执行的耗时异步任务,方便了我们的日常coding(普通的Service则是需要另外创建子线程和控制任务执行顺序)

IntentService的缺点

IntentService,一次只可处理一个任务请求,不可并行,接受到的所有任务请求都会在同一个工作线程执行

IntentService is subject to all the background execution limits imposed with Android 8.0 (API level 26).

翻译:IntentService受到Android 8.0(API级别26)施加的所有[后台执行限制]的约束。

IntentService的未来

!This class was deprecated in API level 30.

IntentService is subject to all the background execution limits imposed with Android 8.0 (API level 26).

Consider using WorkManager or JobIntentService, which uses jobs instead of services when running on Android 8.0 or higher.

官方在最新说明中,提到 IntentService 类将会在API Level 30,也即Android 11中,被废弃掉。作为一个从API Level 3就加入的异步工具,如今官方建议使用JetPack组件中的WorkManager或者JobIntentService类代替它。

IntentService怎么用

IntentService的使用,一般都需要子类继承IntentService,然后重写onHandleIntent()内部逻辑

因为IntentService本质上还是一个Service,所以需要先在注册清单中注册上Service以及需要外部手动开启。

android:name = ".MyIntentService">

AndroidStudio可以通过File-new-Service(IntentService),创建IntentService,IDE会帮我们自动在注册清单注册这个IntentService,为我们的IntentService子类提供了模板实现方法,我们可以在上面省事地修改。

下面为了方便演示,我使用官方提供的IntentService代码模板进行修改和操作:(代码有点长有点渣,请见谅)

//MyIntentService.java

public class MyIntentService extends IntentService {

//用以区分 Intent 的Action名

private static final String ACTION_FOO = "action.FOO";

private static final String ACTION_BAZ = "action.BAZ";

//给Intent传递参数取参的常量值

private static final String EXTRA_PARAM1 = "extra.PARAM1";

private static final String EXTRA_PARAM2 = "extra.PARAM2";

/**

* IntentService构造方法:传入的参数name是作为内部的工作线程名的组成部分

*/

public MyIntentService() {

super("MyIntentService");

Log.i("MyIntentService" , "===created===");

}

@Override

public int onStartCommand(@Nullable Intent intent, int flags, int startId) {

if(intent != null){

Log.i("MyIntentService","Action "+intent.getAction()+" startId: "+startId);

}

return super.onStartCommand(intent, flags, startId);

}

@Override

public void onDestroy() {

super.onDestroy();

Log.i("MyIntentService","===onDestroyed===");

}

/**

* 提供给外界调用,启动任务Foo的方法

* 如果IntentService已经在运行,任务将会进入任务(消息)队列等待排队

* @param context 调用者Context

* @param param1 任务参数1

* @param param2 任务参数2

*/

public static void startActionFoo(Context context, String param1, String param2) {

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

intent.setAction(ACTION_FOO);

intent.putExtra(EXTRA_PARAM1, param1);

intent.putExtra(EXTRA_PARAM2, param2);

context.startService(intent);

}

/**

* 提供给外界调用,启动任务Baz的方法

* 如果IntentService已经在运行,任务将会进入任务(消息)队列等待排队

* @param context 调用者Context

* @param param1 任务参数1

* @param param2 任务参数2

*/

public static void startActionBaz(Context context, String param1, String param2) {

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

intent.setAction(ACTION_BAZ);

intent.putExtra(EXTRA_PARAM1, param1);

intent.putExtra(EXTRA_PARAM2, param2);

context.startService(intent);

}

/**

* IntentService被启动后,会回调此方法

* onHandleIntent内部根据收到的不同Intent执行不同的操作

* @param intent 任务意图

*/

@Override

protected void onHandleIntent(Intent intent) {

if (intent != null) {

final String action = intent.getAction();

if (ACTION_FOO.equals(action)) {

final String param1 = intent.getStringExtra(EXTRA_PARAM1);

final String param2 = intent.getStringExtra(EXTRA_PARAM2);

handleActionFoo(param1, param2);

} else if (ACTION_BAZ.equals(action)) {

final String param1 = intent.getStringExtra(EXTRA_PARAM1);

final String param2 = intent.getStringExtra(EXTRA_PARAM2);

handleActionBaz(param1, param2);

}

Log.i("MyIntentService","Action "+action+" completed");

}

}

/**

* 会在后台的工作线程上执行(耗时)任务Foo

* @param param1 任务参数1

* @param param2 任务参数2

*/

private void handleActionFoo(String param1, String param2) {

Log.i("MyIntentService","handleActionFoo : "+ Thread.currentThread().getName() +

" " + param1 + " "+ param2 );

}

/**

* 会在后台的工作线程上执行(耗时)任务Baz

* @param param1 任务参数1

* @param param2 任务参数2

*/

private void handleActionBaz(String param1, String param2) {

Log.i("MyIntentService","handleActionBaz : "+ Thread.currentThread().getName() +

" " + param1 + " "+ param2 );

}

}

外部如何启用IntentService

可以通过调用context.startService(new Intent(context, MyIntentService.class))

或者调用MyIntentService的静态方法startActionFoo/startActionBaz启动,如果你仔细看其实这两种方式本质上都是相同的代码逻辑。

你可能会问:我平时最常用的bindService()哪去了?这个问题,请接着往下看。

DEMO运行结果

在Activity里,连续调用开启了Intentservice,特别地前两次是相同的Intent和参数

MyIntentService.startActionFoo(this,"DMingO's" ,"blog");

MyIntentService.startActionFoo(this,"DMingO's" ,"blog");

MyIntentService.startActionBaz(this,"DMingO's" ,"Github");

从运行结果可以看出:

IntentService会按照先后顺序给Action编号递增的startId,从1开始。

每启动一次IntentService,onStartCommand(),onHandleIntent()就会被回调一次,但IntentService构造方法只会被调用一次

IntentService主要的操作逻辑都在 onHandleIntent() 中

在主线程启动的IntentService,而onHandleIntent的操作是在指定了线程名的工作线程上执行的

IntentService在所有的任务完成后会自动执行销毁回调onDestroyed,而不用我们手动停止

IntentService的使用场景,很适合需要在后台执行一系列串行执行的耗时任务,不会影响到UI线程,且任务全部完成后会自动销毁。

下面开始探究IntentService这种可以依次执行任务,任务完毕即销毁的背后原理,

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐