Service中onStartCommand回调四种返回值的区别

原文链接:Service中onStartCommand回调四种返回值的区别

服务的两种创建方式

Service 是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。

大家都知道服务的启动方式基本有以下两种:

1、启动

当应用组件(如 Activity)通过调用 startService() 启动服务时,服务即处于”启动”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响。已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。例如,它可能通过网络下载或上传文件。操作完成后,服务会自行停止运行。

2、绑定

当应用组件通过调用 bindService() 绑定到服务时,服务即处于”绑定”状态。绑定服务提供了一个客户端–服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。仅当与另一个应用组件绑定时,绑定服务才会运行。多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。

两种方式创建的服务生命周期如下图,本文的主题便是跟第一种运行方式有关

《Service中onStartCommand回调四种返回值的区别》 service_lifecycle

注意:服务在其托管进程的主线程中运行,它既不创建自己的线程,也不在单独的进程中运行(除非另行指定)。
这意味着,如果服务将执行任何 CPU 密集型工作或阻止性操作(例如 MP3 播放或联网),则应在服务内创建新线程来完成这项工作。
通过使用单独的线程,可以降低发生"ANR"错误的风险,而应用的主线程仍可继续专注于运行用户与 Activity 之间的交互。

组件可以多次调用 startService()onCreate() 回调只会走一次,onStartCommand() 回调会走多次,而 onBind() 回调我们一般会返回null,表示不需要绑定(当然两种运行方式可以同时进行),一旦请求使用 stopSelf()stopService() 停止服务,系统就会尽快销毁服务。

回调方法 onStartCommand()

当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。如果你实现此方法,则在服务工作完成后,需要由你通过调用 stopSelf()stopService() 来停止服务。(如果你只想提供绑定,则无需实现此方法。)
此方法返回类型为 int 型,用于描述系统应该如何在服务终止的情况下继续运行服务,返回值必须是以下常量之一:

1、Service.START_STICKY_COMPATIBILITY

作为 Service.START_STICKY 的兼容版本,不能保证服务被 kill 后再次执行 onStartCommand() 回调。

2、Service.START_STICKY

如果系统在 onStartCommand() 返回后终止服务,则会重建服务并调用 onStartCommand(),但不会重新传递最后一个 Intent。相反,除非有挂起 Intent 要启动服务(在这种情况下,将传递这些 Intent),否则系统会通过空 Intent 调用 onStartCommand()。这适用于不执行命令、但无限期运行并等待作业的媒体播放器(或类似服务)。

3、Service.START_NOT_STICKY

如果系统在 onStartCommand() 返回后终止服务,则除非有挂起 Intent 要传递,否则系统不会重建服务。这是最安全的选项,可以避免在不必要时以及应用能够轻松重启所有未完成的作业时运行服务。

4、Service.START_REDELIVER_INTENT

如果系统在 onStartCommand() 返回后终止服务,则会重建服务,并通过传递给服务的最后一个 Intent 调用 onStartCommand()。任何挂起 Intent 均依次传递。这适用于主动执行应该立即恢复的作业(例如下载文件)的服务。

代码演示

服务类

public class MyService extends Service {

    private static final String TAG = MyService.class.getSimpleName();

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate");
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.e(TAG, "postDelayed");
                // 制造异常,kill 掉该 Service
                int a = 1 / 0;
            }
        }, 3000L);
    }

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

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        Log.e(TAG, "onDestroy");
        super.onDestroy();
    }
}

测试类

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startService(new Intent(MainActivity.this, MyService.class));
    }
}

测试结果

1、使用 START_STICKY_COMPATIBILITY 作为返回值

03-22 20:41:55.619 9311-9311/com.example.test E/MyService: onCreate
03-22 20:41:55.619 9311-9311/com.example.test E/MyService: onStartCommand, intent: Intent { cmp=com.example.test/.MyService }, startId: 1
03-22 20:41:58.619 9311-9311/com.example.test E/MyService: postDelayed
// 服务重新创建,但是没有重启
03-22 20:42:05.079 9489-9489/com.example.test E/MyService: onCreate
03-22 20:42:08.079 9489-9489/com.example.test E/MyService: postDelayed

2、使用 START_STICKY 作为返回值

03-22 20:43:33.219 11068-11068/com.example.test E/MyService: onCreate
03-22 20:43:33.219 11068-11068/com.example.test E/MyService: onStartCommand, intent: Intent { cmp=com.example.test/.MyService }, startId: 1
03-22 20:43:36.229 11068-11068/com.example.test E/MyService: postDelayed
// 服务重新创建并重启,但是 intent 对象被置空了
03-22 20:43:42.199 11233-11233/com.example.test E/MyService: onCreate
03-22 20:43:42.209 11233-11233/com.example.test E/MyService: onStartCommand, intent: null, startId: 2
03-22 20:43:45.209 11233-11233/com.example.test E/MyService: postDelayed

3、使用 START_NOT_STICKY 作为返回值

03-22 20:44:49.459 12437-12437/com.example.test E/MyService: onCreate
03-22 20:44:49.469 12437-12437/com.example.test E/MyService: onStartCommand, intent: Intent { cmp=com.example.test/.MyService }, startId: 1
03-22 20:44:52.469 12437-12437/com.example.test E/MyService: postDelayed
// 服务没有重新创建

4、使用 START_REDELIVER_INTENT 作为返回值

03-22 20:45:49.969 13525-13525/com.example.test E/MyService: onCreate
03-22 20:45:49.969 13525-13525/com.example.test E/MyService: onStartCommand, intent: Intent { cmp=com.example.test/.MyService }, startId: 1
03-22 20:45:52.969 13525-13525/com.example.test E/MyService: postDelayed
// 服务重新创建并启动,intent 对象没有被置空
03-22 20:46:00.879 14792-14792/com.example.test E/MyService: onCreate
03-22 20:46:00.879 14792-14792/com.example.test E/MyService: onStartCommand, intent: Intent { cmp=com.example.test/.MyService }, startId: 1
03-22 20:46:03.889 14792-14792/com.example.test E/MyService: postDelayed
    原文作者:LevisLv
    原文地址: https://www.jianshu.com/p/337c4c8071f6
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞