1-2 Service基础全记录

作者: Shimmer_ | 来源:发表于2019-12-09 21:55 被阅读0次

    [TOC]

    1. 什么是Service

    Service 是与Activity最为相似的组件,主要区别在于Service没有用户界面。Service是Android中实现程序后台运行解决方案,例如音乐的后台播放功能,消息的推送收取,后台文件的下载等等。它适合不与用户交互但需要执行较长周期的任务。这也是它与Activity的最大区别,它不收用户的操作影响,即使程序切换到后台,或打开其他应用程序,也能正常运行

    2.使用场景

    • 后台音乐播放
    • 消息定时推送
    • 后台下载任务
    • 。。。

    3. 生命周期

    Service生命周期.jpg
    方法 说明 补充
    onCreate() 创建服务 只会创建一次
    onStartCommand(intent: Intent?, flags: Int, startId: Int): Int 无绑定启动服务 多次启动,多次回调调用
    返回值决定了服务异常结束情况下的重启操作:1.START_STICKY
    2.START_NOT_STICKY
    3.START_REDELIVER_INTENT
    4.START_STICKY_COMPATIBILITY
    5.START_STICKY
    onBind(intent: Intent): IBinder 绑定启动服务 多次启动,多次回调调用(前提是调用的Intent不一样,否则不会执行多次)
    这里返回的IBinder是服务内部实现并传递给绑定方用于交互的对象
    onUnbind(intent: Intent?): Boolean 解绑服务 多次调用会导致崩溃,解绑时会解绑所有已绑定的调用
    stopService(Intent name) 停止服务 多次调用只执行一次
    onDestroy() 销毁前调用
    stopSelf() 停止自身
    onRebind(intent: Intent?) 重新绑定 触发步骤:先启动,再绑定,再解绑,再次绑定<br />发生条件:
    1. 需要由Activity先startService启动
    2. onUnbind时需要返回true
    3. 传递的intent需要一致
    • START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
    • START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统将会把它置为started状态,系统不会自动重启该服务,直到startService(Intent intent)方法再次被调用;
    • START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入
    • START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。

    4. 使用

    2.1 Service的简要记录图表

    创建与使用


    Service创建与使用.png

    2.2 无绑定启动

    无绑定启动意味着Service与访问者之间无太大关联,同时也意味着它们无法通信或是数据交换,因此Service中执行自有的业务逻辑即可,等待着被销毁或任务结束自行销毁

    //启动
    var intent=Intent(this@MainActivity,SimpleService::class.java)
    startService(intent)
    //停止
    var intent=Intent(this@MainActivity,SimpleService::class.java) intent.action="android.intent.action.SimpleService"
    intent.`package`=this@MainActivity.packageName
    stopService(intent)
    
    调用方调用方法 说明 补充
    startService(Intent service) 启动服务
    stopService(Intent name) 停止服务 多次调用只执行一次

    2.3 绑定启动

    使用绑定启动时,意味着我们需要与Service进行交互,此时的做法是,在Service中先定义出Binder,在Binder中编写需要的功能,例如后台录音功能startRecord()与stopRecord(),然后通过bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE)实现绑定,serviceConnection就是用来获取绑定成功时返回的binder对象,此时便可以进行交互了

    //绑定服务
    bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE)
    //解绑服务
    unbindService(serviceConnection)
    
    var serviceConnection = object : ServiceConnection {
        override fun onServiceDisconnected(p0: ComponentName?) {
            Log.e(TAG,"异常解绑时调用")
        }
    override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
            binder = p1 as SimpleService.CountBinder;
            binder.startRecord()
            binder.stopRecord()
            Log.e(TAG,""+binder.count+"")
        }
    }
    
    
    
    方法 说明 补充
    bindService(Intent service, ServiceConnection conn, int flags) 绑定启动服务 conn是服务绑定需要的中间类,通过它来绑定解绑
    flags是指明绑定服务时是否自动创建(0-否,Context.BIND_AUTO_CREATE-是)
    unbindService(ServiceConnection conn) 解绑服务 多次调用会出现异常
    java.lang.IllegalArgumentException: Service not registered
    ServiceConnection.onServiceDisconnected(ComponentName var1) 服务异常解绑时会调用该方法 正常解绑时不会触发改方法
    ServiceConnection.onServiceConnected(ComponentName var1, IBinder var2) 绑定成功时的回调 var2就可以向下转换为我们需要的binder

    5.其他补充

    服务实际上每个只会存在一个实例,在整个应用程序范围内都是通用的,绑定多个都可以获取到相同的binder实例

    5.1 当Service既被无绑定启动又被绑定启动时,需要执行解绑及停止时才能进入销毁流程

    Android系统机制:一个服务只要被启动或者被绑定了之后,就会一直处于运行状态
    绑定关系实际上是Service将自己的内部对象binder传递给了调用方,并不会完全将Service的生命周期绑定到调用方,调用方调用unBindService方法实际上是切断了与Service的关联

    5.2 错误:*java.lang.IllegalArgumentException: Service Intent must be explicit: Intent {act=android.intent.action.SimpleService }

    Android 5.0 (Lollipop) 之后的规定。 不能用包名的方式定义Service Intent, 而要用显性声明
    想继续使用隐式意图的话,加上包名信息即可

    5.3多次启动或绑定服务时,也只会有一个服务存在,且binder也是同一个

    通过设置不同的type实现绑定多个intent.type=""

    5.4创建前台服务

    与普通的Service类似,唯一不同就是在onCreate中到调用startForeground方法,这样在下拉通知栏中就可以看到该服务

    @Override
    public void onCreate() {
        super.onCreate();
        Intent intent = new Intent(this,    MainActivity.class);
        PendingIntent pendingIntent =       PendingIntent.getActivity(this, 0, intent, 0);
        Notification notification = new     NotificationCompat.Builder(this)
        .setContentTitle("Foreground")
        .setContentText("前台服务")
        .setSmallIcon(R.mipmap.ic_launcher)
        .setContentIntent(pendingIntent)
        .build();
        startForeground(1,notification);
    }
    

    5.5 IntentService

    Service不会专门启动一条单独的进程,与所在应用再同一个进程中

    Service也不是专门一条新的线程,因此不应直接再Service中直接处理耗时任务

    • IntentService使用队列来管理请求 Intent
      每当调用方通过Intent请求启动IntentService时,IntentService将该Intent加入队列中,然后开启一条新的worker线程处理该Intent。对于异步的startService请求,IntentService会按次序依次处理队列中的Intent,该线程保证同一时刻只处理一个Intent。

    • IntentService使用新的worker线程处理Intent请求,onHandleIntent(@Nullable Intent intent) 方法中即在子线程中运行
      因此IntentService不好阻塞主线程,自己就可以处理耗时任务

    • 默认实现onBind ,返回null

    • 默认实现 onStartCommand,将请求Intent添加到队列中

    • 自定义实现

      //同样需要在清单文件中注册
      public class MyIntentService extends IntentService {
          private static final String TAG = "MyIntentService";
      
          public MyIntentService() {
              super("MyIntentService");
          }
          @Override
          protected void onHandleIntent(@Nullable Intent intent) {
              Log.e(TAG, "onHandleIntent: " );
          }
      }
      
    • 执行完任务后自动停止

    相关文章

      网友评论

        本文标题:1-2 Service基础全记录

        本文链接:https://www.haomeiwen.com/subject/acgigctx.html