Service基础全记录

1. 什么是Service

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

2.使用场景

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

3. 生命周期

Service生命周期

方法说明补充
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?)重新绑定触发步骤:先启动,再绑定,再解绑,再次绑定
发生条件:
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: " );
        }
    }
    
  • 执行完任务后自动停止

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值