整理之Service
阅读原文时间:2023年07月08日阅读:1

Service

基础

一个Service的基本结构
class MyService : Service() {
    private val mBinder = MyBinder()

    override fun onCreate() {
        super.onCreate()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onBind(intent: Intent): IBinder {
        return mBinder
    }

    override fun onUnbind(intent: Intent?): Boolean {
        return super.onUnbind(intent)
    }

    override fun onDestroy() {
        super.onDestroy()
    }

    class MyBinder:  IBinder() {
        //实现对Service的操作,如下载操作的开始暂停等
    }
}


<service android:name=".myservice"
            android:enabled="true"
            android:exported="true"
            android:icon="@drawable/background_blue"
            android:label="string"
            android:process="string"
            android:permission="string">
 </service>

启动和关闭:启动后无法操作

val intent = Intent(this, MyService::class)
startService(intent)
stop(service)
//每次调用startService都会调用一次onStartCommand,但是onCreate只会调用一次
//只有调用stopService/stopSelf和被系统杀死才会停止服务,startServicec 并不依附于启动它的Context

绑定和解除绑定:可以通过Binder进行操作

private val mBinder = MyService.MyBinder()
private val connection = ServiceConnection() {
    @Override
    fun onServiceConnected(name: ComponentName, service: IBinder) {
        mBinder = service as MyService.MyBinder
    }
    @Override
    onServiceDisconnected(name: ComponentName) { }
}
val intent = Intent(this, MyService::class)
bindService(intent, connection, Service.BIND_AUTO_CREATE)
unbindService(service)
//bindService时不会调用onStartCommand
//当Context不存在后,Service也会终止(配置改变时也会停止Service)

两种启动方式的生命周期:

Android5.0后,隐式启动Service $\color{blue}文字颜色{blue}$

<service&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;android:name="com.dbjtech.acbxt.waiqin.UploadService"&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;android:enabled="true"&nbsp;>&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;<intent-filter&nbsp;android:priority="1000"&nbsp;>&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<action&nbsp;android:name="com.dbjtech.myservice"&nbsp;/>&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;</intent-filter>&nbsp;&nbsp;
</service>&nbsp;


val intent = Intent().apply {
    setAction("com.android.ForegroundService");
    setPackage(getPackageName());//设置应用的包名
}
startService(intent);

粘性服务与非粘性服务

服务的粘性体现在:当服务被系统杀死后,粘性服务会自动重启并执行onStartCommand,非粘性服务不会。

通过onStartCommand的返回值来设置是否粘性,可选择的值为:

参数

含义

START_STICKY

如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。

START_NOT_STICKY

使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。

START_REDELIVER_INTENT

重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。

START_STICKY_COMPATIBILITY

START_STICKY的兼容版本,但不保证服务被kill后一定能重启。

默认情况下,通过startService启动的服务为粘性的。

前台服务

参考这篇文章

官方描述:前台服务是那些被认为用户知道(用户所认可的)且在系统内存不足的时候不允许系统杀死的服务。前台服务必须给状态栏提供一个通知,它被放到正在运行(Ongoing)标题之下——这就意味着通知只有在这个服务被终止或从前台主动移除通知后才能被解除。

使用方法

在onCommand中创建通知

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
  // 在API11之后构建Notification的方式
  Notification.Builder builder = new Notification.Builder
    (this.getApplicationContext()); //获取一个Notification构造器
  Intent nfIntent = new Intent(this, MainActivity.class);

  builder.setContentIntent(PendingIntent.
    getActivity(this, 0, nfIntent, 0)) // 设置PendingIntent
    .setLargeIcon(BitmapFactory.decodeResource(this.getResources(),
      R.mipmap.ic_large)) // 设置下拉列表中的图标(大图标)
    .setContentTitle("下拉列表中的Title") // 设置下拉列表里的标题
    .setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标
    .setContentText("要显示的内容") // 设置上下文内容
    .setWhen(System.currentTimeMillis()); // 设置该通知发生的时间
  
  Notification notification = builder.build(); // 获取构建好的Notification
  notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音

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

启动与停止:

// 参数一:唯一的通知标识;参数二:通知消息。
startForeground(110, notification);// 开始前台服务
stopForeground(true);// 停止前台服务--参数:表示是否移除之前的通知

IntentService

参考这篇文章
1.与Service的区别

Service运行在主线程,内部不能执行耗时操作。但IntentService在执行onCreate 操作的时候,内部开了一个线程,去你执行你的耗时操作

2.特点

会创建独立的 worker 线程来处理所有的 Intent 请求

会创建独立的 worker 线程来处理 onHandleIntent() 方法实现的代码,无需处理多线程问题

所有请求处理完成后,IntentService 会自动停止,无需调用 stopSelf() 方法停止 Service

为 Service 的 onBind() 提供默认实现,返回 null

为 Service 的 onStartCommand 提供默认实现,将请求 Intent 添加到队列中

3.使用

编写类:

class MyIntentService : IntentService("MyIntentService") {
    override fun onHandleIntent(intent: Intent?) {
        when (intent?.action) {
            。。。
        }
    }
}

注册:

<service android:name="com.example.intentservicetest.MyService" />

启动:

val intent = Intent(MainActivity.this, MyService.class);
startService(intent);
//所有的请求的处理都在一个工作线程中完成 , 它们会交替执行(但不会阻塞主线程的执行),一次只能执行一个请求。
4.执行过程
  • 每次启动该服务并不是马上处理你的工作,而是首先会创建对应的Looper、Handler,并且在 MessageQueue 中添加附带客户 Intent 的 Message 对象。
  • 当 Looper 发现有 Message 的时候,会在onHandleIntent((Intent)msg.obj) 中得到 Intent 对象,调用你的处理程序,处理完后即会停止自己的服务。

Intent 的生命周期跟你的处理的任务是一致的,所以这个类用下载任务中非常好,下载任务结束后服务自身就会结束退出。