清晰地理解Service

1. Service的start和bind有什么区别?

Service有两种形式: startedbound.

当一个组件调用startService()后, Service就处于”started”状态. 组件每次调用startService()方法, Service都会调用onStartCommand()方法一次, 只有第一次调用startService()方法时, 会调用onCreate()方法.
一旦start后, Service就会无限期地运行在后台, 即便是start这个Service的那个组件已经销毁了.通常情况下, 一个处于started状态的Service会执行一个单独的任务并且不会给调用者返回结果.

通过start方式启动的Service, 要停止服务就需要自己调用stopSelf()方法或者是另外的组件调用stopService()方法.不管调用了多少次startService()方法, 只要调用一个stopSelf()方法或者stopService()方法, Service会马上停止.

当一个组件调用bindService()后, Service就处于”bound”状态.组件只有在第一次调用bindService()方法时, Service才会调用onCreate()方法和onBind()方法,换句话说, 即便是多次调用bindService()方法, Service也不会多回调onCreate()方法和onBind()方法.

同一个组件多次bind一个service, 只需要调用一次unbindService()方法,即可完成unbind; 不同的几个组件都bind一个service, 那么这些组件需要分别调用一次unbindService方法, 才可以完成unbind.

2. 同一个Service, 先startService, 然后再bindService, 如何把它停止掉?

需要调用一次stopService()方法和unbindService()方法, 把它停止掉.这两个方法没有调用顺序.
先调用stopService()方法,再调用unbindService()方法的日志:

D/MyService: onCreate: 
D/MyService: onStartCommand: intent = Intent { cmp=com.wzc.g1_service/.MyService }, flags = 0, startId = 1
D/MyService: onBind: intent = Intent { cmp=com.wzc.g1_service/.MyService }
D/MyService: onUnbind: intent = Intent { cmp=com.wzc.g1_service/.MyService }
D/MyService: onDestroy: 

当调用stopService()时,是没有日志输出的; 当调用unbindService()时, 会回调onUnbind和onDestroy

先调用unbindService()方法,再调用stopService()方法的日志:

D/MyService: onCreate: 
D/MyService: onStartCommand: intent = Intent { cmp=com.wzc.g1_service/.MyService }, flags = 0, startId = 1
D/MyService: onBind: intent = Intent { cmp=com.wzc.g1_service/.MyService }
D/MyService: onUnbind: intent = Intent { cmp=com.wzc.g1_service/.MyService }
D/MyService: onDestroy: 

当调用unbindService方法时, 会回调onUnbind方法; 当调用stopService()时, 会回调onDestroy方法.

3. 你有注意到Service的onStartCommand方法的返回值吗? 不同的返回值有什么区别?

注意到onStartCommand方法有4种返回值.

    /**
     * 这是START_STICKY的兼容版本, 不保证服务被杀死后, onStartCommand方法会被再次调用
     */
    public static final int START_STICKY_COMPATIBILITY = 0;

    /**
     *  如果Service处于started状态(在从onStartCommand方法返回后)时,它的进程被杀死,那么把它保留在
     *  started状态但是不保存传递的intent.之后系统会尝试重新创建该Service. 因为Service处于started状态,
     *  所以在创建了新的service实例后, 一定会回调onStartCommand方法; 如果没有任何pending类型的启动命令
     *  传递给该Service, 那么传递过来的intent参数就为null, 因为要注意在onStartCommand中对这种intent做非空校验.
     *
     *  这种模式适用于明显开始和停止Service,来运行任意长度的时间的情况,例如一个用于执行后台音乐播放的Service
     */
    public static final int START_STICKY = 1;

    /**
     * 如果Service处于started状态(在从onStartCommand方法返回后)时,它的进程被杀死,并且没有新的start类型的intent
     * 传递给Service, 那么就把Service带出started状态并且不会再重新创建Service, 除非将来有一个显示调用startService方法.
     * Service不会再回调带有intent值为null的onStartCommand方法, 这是因为如果没有pending类型的intent要传递, Service
     * 不会再次启动.
     * 
     * 这个模式适用于Service被start后,要做一些任务, 但是当内存有压力时可以停止Service,之后
     * 显式再次启动自己来做更多的任务的情况. 这样的Service的一个例子是轮询来自服务器的数据的
     * Service: 通过定时器开始服务设定一个每N分钟轮询一次的定时器. 当定时器调用服务的onStartCommand
     * 方法时, 服务会设定一个新的N分钟后的定时器,并且开启新的线程执行网络操作. 如果在做检查的过程中, 
     * 服务的进程被杀死, 那么服务将不会被重启直到定时器触发.
     */
    public static final int START_NOT_STICKY = 2;

    /**
     *  如果Service处于started状态(在从onStartCommand方法返回后)时,它的进程被杀死, 那么
     *  服务会被安排重启,并且最后传递过来的intent会被再次通过onStartCommand方法传递给服务.
     *  这个Intent会保持着重传递的计划直到服务调用了带有传递给onStartCommand方法的startId的
     *  stopSelf(int)方法. Service不会再回调带有intent值为null的onStartCommand方法, 因为
     *  服务将会被重启如果它没有处理完所有传递过来的intent(并且在重启时, 任何pending类型的
     *  intent会被传递)
     */
    public static final int START_REDELIVER_INTENT = 3;

4. Service的生命周期方法onCreate, onStartCommand, onBind等运行在哪个线程?

Service运行在它所在的进程的主线程–Service不会创建它自己的线程也不会运行在一个单独的进程(除非单独制定).这意味着, 如果Service在执行耗时操作, 就应该在Service中创建新的线程来执行那些操作, 这样可以减少应用出现ANR的风险.
打印日志可以看出,每个方法都是运行在主线程的, 如下:

D/MyService: onCreate: thread name = main
D/MyService: onStartCommand: intent = Intent { cmp=com.wzc.g1_service/.MyService }, flags = 0, startId = 1thread name = main
D/MyService: onBind: intent = Intent { cmp=com.wzc.g1_service/.MyService }, thread name = main
D/MyService: onUnbind: intent = Intent { cmp=com.wzc.g1_service/.MyService }, thread name = main
D/MyService: onDestroy: thread name = main

5. Service与Thread有什么关系?

Thread是程序执行的最小单元, 它是分配CPU的基本单位. 可以用Thread来执行一些异步的操作.
Service是Android的四大组件之一, 如果是LocalService, 那么它会运行在主进程的main线程上; 如果是RemoteService, 那么它会运行在独立进程的main线程上.

Thread的运行是独立于Activity的, 也就是说当一个Activity被finish后, 如果你没有主动停止Thread或者Thread里的run方法没有执行完毕的话, Thread会一直执行. 但是, 当Activity被finish后, 就没有任何办法可以再重新获取之前创建的子线程的实例. 同时, 也不能在不同的Activity中对同一个Thread进行控制.

Service却不一样. 所有的Activity都可以与Service进行关联, 然后可以方便地控制Service. 实际上, 在任何有Context的地方也是这样的, 只需要调用Context.startService(), Context.stopService, Context.bindService, Context.unbindService. 也可以在Service里面注册BroadcastReceiver, 在其他地方通过发送广播来控制它, 这些是Thread做不到的.

参考资料

Android中的Service的使用详解

猜你喜欢

转载自blog.csdn.net/willway_wang/article/details/79823022
今日推荐