Android 四大组件之一 Service
Android 四大组件之一 Service
Android Service是具有生命周期的,具有三种。
- start
- bind
- start 和 bind 混合
混合是生命周期问题
[startService()] → onCreate() → onStartCommand() → running
[bindService()] → onBind() → bound
[unbindService()] → onUnbind() → still running
[stopService()] → onDestroy()
不管是调用stopService还是unbindService谁最后调用,service才被销毁。
service 使用
定义
HelloService.kt
internal class HelloService internal constructor() : LifecycleService() {
override fun onCreate() {
super.onCreate()
Log.i(TAG, "onCreate...")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId).apply {
Log.i(TAG, "onStartCommand intent: $intent, flags: $flags, startId: $startId value: $this")
}
}
override fun onBind(intent: Intent): IBinder? {
super.onBind(intent)
Log.i(TAG, "onBind intent: $intent...")
return HelloBinder()
}
override fun onRebind(intent: Intent?) {
Log.i(TAG, "onRebind -> intent: $intent")
super.onRebind(intent)
}
override fun onUnbind(intent: Intent?): Boolean {
return super.onUnbind(intent).apply {
Log.i(TAG, "onUnbind -> intent: $intent value: $this")
}
}
override fun onDestroy() {
Log.i(TAG, "onDestroy...")
super.onDestroy()
}
internal class HelloBinder : Binder() {
internal fun getHello(): String {
return "Hello: ${Random.nextInt(until = 1000)}"
}
}
}
ServiceScreen.kt
@Composable
internal fun ServiceScreen(
modifier: Modifier,
snackBarHostState: SnackbarHostState
) {
val context: Context = LocalContext.current
val coroutineScope: CoroutineScope = rememberCoroutineScope()
var helloBinder: HelloService.HelloBinder? by remember {
mutableStateOf(value = null)
}
val connection: ServiceConnection by remember {
mutableStateOf(value = object : ServiceConnection {
override fun onServiceConnected(
name: ComponentName?,
service: IBinder?
) {
helloBinder = service as? HelloService.HelloBinder
Log.i(TAG, "onServiceConnected -> name: $name, service: $service")
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.i(TAG, "onServiceDisconnected -> name: $name")
}
})
}
Column(
modifier = modifier.fillMaxSize()
) {
Text(
text = "启动服务",
Modifier
.padding(top = 10.dp)
.background(color = Color.Black, shape = RoundedCornerShape10)
.padding(all = 5.dp)
.clickable {
// context.startService(Intent(context, HelloService::class.java))
context.bindService(
Intent(context, HelloService::class.java),
connection,
Context.BIND_AUTO_CREATE
)
val message = helloBinder?.getHello()
Log.i(TAG, "ServiceScreen -> message: $message")
},
color = Color.White
)
Text(
text = "关闭服务",
Modifier
.padding(top = 10.dp)
.background(color = Color.Black, shape = RoundedCornerShape10)
.padding(all = 5.dp)
.clickable {
// context.stopService(Intent(context, HelloService::class.java))
context.unbindService(connection)
},
color = Color.White
)
}
}
注册
<service android:name=".service.HelloService"/>
OnRebind
onRebind方法在Service没有销毁的时候,再次被绑定时触发
onStart->onBind->onUnbind->onBind(触发)->onUnbind->stopService->onDestroy
HelloService.kt
private const val TAG: String = "HelloService"
internal class HelloService internal constructor() : LifecycleService() {
companion object {
internal fun bindService(context: Context, connection: ServiceConnection){
val isSuccess: Boolean = context.bindService(Intent(context, HelloService::class.java), connection, Context.BIND_AUTO_CREATE)
Log.i(TAG, "bindService isSuccess: $isSuccess")
}
internal fun unbindService(context: Context, connection: ServiceConnection) {
context.unbindService(connection)
}
internal fun startService(context: Context) {
context.startService(Intent(context, HelloService::class.java))
}
internal fun stopService(context: Context) {
context.stopService(Intent(context, HelloService::class.java))
}
}
override fun onCreate() {
super.onCreate()
Log.i(TAG, "onCreate...")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId).apply {
Log.i(TAG, "onStartCommand intent: $intent, flags: $flags, startId: $startId value: $this")
}
}
override fun onBind(intent: Intent): IBinder? {
super.onBind(intent)
Log.i(TAG, "onBind intent: $intent...")
return HelloBinder()
}
override fun onRebind(intent: Intent?) {
Log.i(TAG, "onRebind -> intent: $intent")
super.onRebind(intent)
}
override fun onUnbind(intent: Intent?): Boolean {
return true
// return super.onUnbind(intent).apply {
// Log.i(TAG, "onUnbind -> intent: $intent value: $this")
// }
}
override fun onDestroy() {
Log.i(TAG, "onDestroy...")
super.onDestroy()
}
internal class HelloBinder : Binder() {
internal fun getHello(): String {
return "Hello: ${Random.nextInt(until = 1000)}"
}
}
}
ServiceScreen.kt
package edu.tyut.webviewlearn.ui.screen
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import edu.tyut.webviewlearn.service.HelloService
import edu.tyut.webviewlearn.ui.theme.RoundedCornerShape10
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
private const val TAG: String = "ProviderScreen"
@Composable
internal fun ServiceScreen(
modifier: Modifier,
snackBarHostState: SnackbarHostState
) {
val context: Context = LocalContext.current
val coroutineScope: CoroutineScope = rememberCoroutineScope()
var helloBinder: HelloService.HelloBinder? by remember {
mutableStateOf(value = null)
}
val connection: ServiceConnection by remember {
mutableStateOf(value = object : ServiceConnection {
override fun onServiceConnected(
name: ComponentName?,
service: IBinder?
) {
helloBinder = service as? HelloService.HelloBinder
Log.i(TAG, "onServiceConnected -> name: $name, service: $service")
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.i(TAG, "onServiceDisconnected -> name: $name")
}
})
}
Column(
modifier = modifier.fillMaxSize()
) {
Text(
text = "启动服务",
Modifier
.padding(top = 10.dp)
.background(color = Color.Black, shape = RoundedCornerShape10)
.padding(all = 5.dp)
.clickable {
// context.startService(Intent(context, HelloService::class.java))
HelloService.bindService(context, connection)
HelloService.startService(context)
val message = helloBinder?.getHello()
Log.i(TAG, "ServiceScreen -> message: $message")
},
color = Color.White
)
Text(
text = "关闭服务",
Modifier
.padding(top = 10.dp)
.background(color = Color.Black, shape = RoundedCornerShape10)
.padding(all = 5.dp)
.clickable {
// context.stopService(Intent(context, HelloService::class.java))
context.unbindService(connection)
},
color = Color.White
)
}
}
跨进程通信
Service可以跨进程通信。
server app:
声明
<permission android:name="edu.tyut.webviewlearn.helloService"/>
<application
<service android:name=".service.HelloService"
android:exported="true"
android:permission="edu.tyut.webviewlearn.helloService" />
</application>
client app:
声明
<uses-permission android:name="edu.tyut.webviewlearn.helloService"/>
使用
start方式,这种方式仅允许前台启动,否则android.app.BackgroundServiceStartNotAllowedException
@Composable
internal fun ServiceScreen(
navHostController: NavHostController,
snackBarHostState: SnackbarHostState,
){
val context: Context = LocalContext.current
Column(
modifier = Modifier.fillMaxSize()
){
Text(
text = "连接Service",
Modifier
.padding(top = 10.dp)
.background(color = Color.Black, shape = RoundedCornerShape10)
.padding(all = 5.dp)
.clickable {
context.startService(Intent().setClassName("edu.tyut.webviewlearn", "edu.tyut.webviewlearn.service.HelloService"))
},
color = Color.White
)
Text(
text = "断开Service",
Modifier
.padding(top = 10.dp)
.background(color = Color.Black, shape = RoundedCornerShape10)
.padding(all = 5.dp)
.clickable {
context.stopService(Intent().setClassName("edu.tyut.webviewlearn", "edu.tyut.webviewlearn.service.HelloService"))
},
color = Color.White
)
}
}
bind方式
package edu.tyut.helloktorfit.ui.screen
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import android.util.Log
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import androidx.navigation.NavHostController
import edu.tyut.helloktorfit.ui.theme.RoundedCornerShape10
private const val TAG: String = "ServiceScreen"
@Composable
internal fun ServiceScreen(
navHostController: NavHostController,
snackBarHostState: SnackbarHostState,
){
val context: Context = LocalContext.current
val connection: ServiceConnection by remember {
mutableStateOf(value = object : ServiceConnection {
override fun onServiceConnected(
name: ComponentName?,
service: IBinder?
) {
// helloBinder = service as? HelloService.HelloBinder
Log.i(TAG, "onServiceConnected -> name: $name, service: $service")
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.i(TAG, "onServiceDisconnected -> name: $name")
}
})
}
Column(
modifier = Modifier.fillMaxSize()
){
Text(
text = "连接Service",
Modifier
.padding(top = 10.dp)
.background(color = Color.Black, shape = RoundedCornerShape10)
.padding(all = 5.dp)
.clickable {
val isSuccess: Boolean = context.bindService(
Intent().setClassName(
"edu.tyut.webviewlearn",
"edu.tyut.webviewlearn.service.HelloService"
), connection, Context.BIND_AUTO_CREATE
)
Log.i(TAG, "ServiceScreen -> isSuccess: $isSuccess")
// context.startService(Intent().setClassName("edu.tyut.webviewlearn", "edu.tyut.webviewlearn.service.HelloService"))
},
color = Color.White
)
Text(
text = "断开Service",
Modifier
.padding(top = 10.dp)
.background(color = Color.Black, shape = RoundedCornerShape10)
.padding(all = 5.dp)
.clickable {
// context.stopService(Intent().setClassName("edu.tyut.webviewlearn", "edu.tyut.webviewlearn.service.HelloService"))
context.unbindService(connection)
},
color = Color.White
)
}
}
当服务启动时,才能成功绑定。
通信
你可以使用Messager、AIDL实现跨进程 通信。

Android 四大组件之一 Service
浙公网安备 33010602011771号