Kotlin-Service技术点

1.Service的定义

Service是Android中实现程序后台运行的解决方案,它非常适合执行那些不需要和用户交互还要长期运行的任务。

2.Service运行所在环境

Service不不是运行在独立的进程,而是依赖于创建Service时所在应用进程,当所在的应用程序进程被杀掉时,所有依赖该进程的Service都会被杀死。

3.Service执行代码逻辑是否会阻塞主线程

Service并不会自动开启线程,所有代码逻辑默认运行在主线程,如果直接执行耗时的任务就会有阻塞主线程的风险,所以如果需要执行耗时操作需要创建子线程进行处理。

4.创建MyService时Exported和Enabled参数

Exported这个参数表示是否暴露给外部程序使用

Enabled这个参数表示服务是否启用这个服务

5.启动与停止服务方法一

//启动服务
val intent = Intent(this,MyService::class.java)
startService(intent)

//停止服务
 val intent = Intent(this,MyService::class.java)
 stopService(intent)

这样就可以启动Service,服务会执行onCreate方法和onStartCommand方法,需要首次进行初始化的内容放在onCreate方法里边执行。

服务内部也可以调用stopSelf方法来停止服务。

多次调用startService,onCreate方法只会执行一次,onStartCommand每次启动都会执行。

6.启动与断开服务方法二

 private val connection = object : ServiceConnection {

        override fun onServiceDisconnected(name: ComponentName?) {
            Log.d("MainActivity","onServiceDisconnected")
        }

        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            Log.d("MainActivity","onServiceConnected")
        }

    }
	
//bind service
var intent=Intent(this,MyService::class.java)
bindService(intent,connection, Context.BIND_AUTO_CREATE)

//unbind Service
unbindService(connection)

通过bindService启动服务,需要先定义一个ServiceConnection,这个connection需要重写onServiceConnected这个方法服务连接的时候会回调,另外一个是onServiceDisconnected,这个方法是断开服务的时候回调。

通过bindService启动服务,Service会执行onCreate、onBind方法然后执行onServiceConnected方法。

如果通过两个方式启动了服务,需要调用stopService和unBinderService才会彻底的停掉服务的。

7.Activity和Service进行通信

如果需要进行通信,比如在activity中需要得到服务的执行过程就需要使用bindService的方式启动服务

class MyService : Service() {
	
    //定义并初始化binder成员变量
    private val mBinder = DownloadBinder()
	
    //在onBinder中返回会binder对象
    override fun onBind(intent: Intent): IBinder {
        Log.d("MyService","onBind")
       return mBinder
    }

    override fun onCreate() {
        super.onCreate()
        Log.d("MyService","onCreate")
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.d("MyService","onStartCommand")
        return super.onStartCommand(intent, flags, startId)
        //执行到某个条件,可以调用这个方法自动停止Service
		//停止服务的方法
//       stopSelf()
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("MyService","onDestroy")
    }
	
    //定义binder内部类
    class DownloadBinder:Binder(){
        private var i:Int=0
        fun startDownload(){
            Log.d("MyService","startDownload")
            i++
        }

        fun getProgress():Int{
            Log.d("MyService","getProgress = "+i)
            return i
        }
    }


}

接下来就是在activity通过binder来得到需要用到的内容

private val connection = object : ServiceConnection {

    override fun onServiceDisconnected(name: ComponentName?) {
        Log.d("MyService","onServiceDisconnected")
    }

    override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
        Log.d("MyService","onServiceConnected")
        downloadBinder=service as MyService.DownloadBinder
        downloadBinder.startDownload()
        downloadBinder.getProgress()
    }

}

fun onBind(view:View){
    var intent=Intent(this,MyService::class.java)
    bindService(intent,connection, Context.BIND_AUTO_CREATE)

}

在onServiceConnected中得到binder对象,通过这个对象就可以获取到服务的执行进度等需要的信息。

8.前台服务

从Android8.0系统开始,只有当应用保持在前台可见状态的情况下,Service才能保证稳定运行,一旦应用程序进入后台之后,Service随时都可能被系统回收。如果希望Service一直保持运行状态,就需要考虑使用前台服务。前台服务和普通服务的区别是,前台服务一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏可以清晰看到详细信息。

class MyService : Service() {

   ...
    
   override fun onCreate() {
        super.onCreate()
        Log.d("MyService","onCreate")

        val manager=getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.O){
            val channel=NotificationChannel("my_service","前台服务",NotificationManager.IMPORTANCE_DEFAULT)
            manager.createNotificationChannel(channel)
        }

        val intent=Intent(this,MainActivity::class.java)
        val pi=PendingIntent.getActivity(this,0,intent,0)
        val builder=NotificationCompat.Builder(this,"MyService")

        builder.setContentTitle("this is content title")
            .setContentInfo("this is content info")
            .setSmallIcon(R.mipmap.ic_launcher)
            .setLargeIcon(BitmapFactory.decodeResource(resources,R.mipmap.ic_launcher))
            .setContentIntent(pi)


        if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.O) {
            builder.setChannelId("my_service")
        }
        val notification=builder.build()
        startForeground(1, notification)
    }

    ...
}

只需要在onCreate方法中添加相关的代码逻辑就可以,另外在Android9.0以上,启动前台服务需要申明权限才行

android.permission.FOREGROUND_SERVICE

做好上面这些之后,执行startService就可以启动前台服务了……

源码地址

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这个问题和之前的问题基本相同,只是多了一个 dispatch 处理的步骤。以下是实现的步骤: 1. 创建 AIDL 接口 创建一个 AIDL 文件,例如 `TaskManagerService.aidl`,定义接口方法 `addTask()` 和 `getTask()`,用于添加任务和获取任务。 ``` // TaskManagerService.aidl package com.example.taskmanager; interface TaskManagerService { void addTask(String task); String getTask(); } ``` 2. 创建服务端 Service 创建一个服务端 Service,例如 `TaskManagerService.kt`,实现 AIDL 接口并处理客户端的请求。在服务端的 `onBind()` 方法中返回一个 `TaskManagerService.Stub` 对象,该对象实现了 AIDL 接口。同时,我们创建一个线程来轮询任务栈,并使用 `Handler` 将任务分发到主线程进行处理。 ``` // TaskManagerService.kt class TaskManagerService : Service() { private val taskStack = Stack<String>() private val binder = object : TaskManagerService.Stub() { override fun addTask(task: String) { taskStack.push(task) } override fun getTask(): String? { return if (taskStack.isNotEmpty()) taskStack.pop() else null } } private val handler = Handler(Looper.getMainLooper()) { // Handle task here true } private val dispatcher = Thread { while (true) { val task = taskStack.pop() if (task != null) { handler.sendMessage(handler.obtainMessage(0, task)) } } } override fun onCreate() { super.onCreate() dispatcher.start() } override fun onBind(intent: Intent): IBinder? { return binder } } ``` 在这个例子中,我们使用了一个栈来保存任务。在 `addTask()` 方法中,我们将任务添加到栈顶;在 `getTask()` 方法中,我们从栈顶获取一个任务并将其弹出。如果栈为空,则返回 null。 同时,我们创建了一个 `handler` 对象和一个 `dispatcher` 线程。在 `dispatcher` 线程中,我们不断地轮询任务栈,如果有任务就将任务发送到 `handler` 对象中。在 `handler` 对象中,我们可以处理任务,并在主线程中进行相应的操作。 3. 在 AndroidManifest.xml 中注册服务 在 AndroidManifest.xml 文件中注册服务,例如: ``` <service android:name=".TaskManagerService" android:exported="true" /> ``` `android:exported="true"` 表示服务可以被其他应用程序访问。 4. 创建客户端 创建一个客户端应用,例如 `TaskManagerClient.kt`,通过 `bindService()` 方法绑定服务端的 TaskManagerService,并通过 AIDL 接口调用服务端的方法。 ``` // TaskManagerClient.kt class TaskManagerClient : ServiceConnection { private lateinit var taskManager: TaskManagerService override fun onServiceConnected(name: ComponentName?, service: IBinder?) { taskManager = TaskManagerService.Stub.asInterface(service) taskManager.addTask("Task 1") taskManager.addTask("Task 2") taskManager.addTask("Task 3") } override fun onServiceDisconnected(name: ComponentName?) { // Do nothing } fun start(context: Context) { val intent = Intent() intent.setClassName("com.example.taskmanager", "com.example.taskmanager.TaskManagerService") context.bindService(intent, this, Context.BIND_AUTO_CREATE) } } ``` 在这个例子中,我们在 `onServiceConnected()` 方法中获取服务端的 TaskManagerService 对象,并添加一些任务到任务栈中。 5. 创建 dispatch 处理方法 在客户端应用程序中,我们需要创建一个 dispatch 处理方法,用于处理服务端发来的任务。例如: ``` // TaskManagerClient.kt class TaskManagerClient : ServiceConnection { // ... private val handler = object : Handler(Looper.getMainLooper()) { override fun handleMessage(msg: Message) { val task = msg.obj as String // Dispatch task here } } fun start(context: Context) { // ... while (true) { val task = taskManager.getTask() if (task != null) { handler.sendMessage(handler.obtainMessage(0, task)) } else { break } } } } ``` 在这个例子中,我们创建了一个 `handler` 对象,在其中实现了一个 `handleMessage()` 方法,用于处理服务端发来的任务。在 `start()` 方法中,我们不断地调用 `getTask()` 方法获取任务,并将任务发送到 `handler` 对象中进行处理。 最后,我们可以在客户端应用程序的主 Activity 中启动客户端: ``` // MainActivity.kt class MainActivity : AppCompatActivity() { private lateinit var taskManagerClient: TaskManagerClient override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) taskManagerClient = TaskManagerClient() taskManagerClient.start(this) } } ``` 这样,我们就实现了一个使用 Kotlin 和 AIDL 技术的服务端,可以接收来自多个客户端的请求,并在一个线程中处理请求,实现任务栈的功能,并使用 dispatch 处理方法将任务分发到主线程进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值