Android:如何在不同进程中运行的activity和service之间进行通信?



我开始一个service在不同的processactivityservice被设计为即使在应用程序关闭时也能运行。从activity启动service后,我关闭了应用程序。现在,当我重新打开应用程序时,service可能正在运行,也可能没有运行。但是我没有办法知道service是否在运行。我怎样才能做到呢?

仅供参考:我已经检查了SO上的所有相关答案,但是当服务在不同的进程中运行时,它们都不起作用。这是我得到的最接近的答案了。但是这个答案似乎有缺陷,我也想听听你的意见。

下面是我正在做的:

AndroidManifest.xml

<service
android:name=".services.MyService"
android:enabled="true"
android:exported="false"
android:process=":backgroundProcess" />

MainApplication.kt(目的:只有一个SettingsRepository类的实例)

class MainApplication : Application() {
val settingsRepository by lazy { SettingsRepository(this) }
}

SettingsRepository.kt(目的:在首选数据存储中保存服务的运行状态)

class SettingsRepository(context: Context) {
private val dataStore = context.createDataStore(name = "settings_prefs")
companion object {
val SERVICE_STATE_KEY = booleanPreferencesKey("SERVICE_STATE_KEY")
}
suspend fun saveServiceStateToDataStore(state: Boolean) {
dataStore.edit {
it[SERVICE_STATE_KEY] = state
}
}
val getServiceStateFromDataStore: Flow<Boolean> = dataStore.data.map {
val state = it[SERVICE_STATE_KEY] ?: false
state
}
}

Service.kt

private lateinit var settingsRepository: SettingsRepository
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
settingsRepository = (application.applicationContext as MainApplication).settingsRepository

saveStateToDataStore(true)
return START_REDELIVER_INTENT
}
private fun saveStateToDataStore(state: Boolean): Job {
return CoroutineScope(Dispatchers.IO).launch {
settingsRepository.saveServiceStateToDataStore(state)
}
}

Activity.kt

private fun observeDataFromViewModel() {
mainViewModel.readServiceStateFromRepository.observe(this, {state ->
Toast.makeText(this, "Service state changed to $state", Toast.LENGTH_SHORT).show()
// should get the new data when service stores it in onStartCommand but doesn't get it
// maybe because the service doesn't stores the data for some reason I am not aware of.

})

}
private fun handleClickListener() {
btn_start_service.setOnClickListener {
startForegroundService(serviceIntent)
}
}
btn_stop_service.setOnClickListener {
mainViewModel.saveServiceState(false)
stopService(serviceIntent)
}
}

ViewModel.kt

class MainViewModel(application: Application) : AndroidViewModel(application) {
private val settingsRepository = (application.applicationContext as MainApplication).settingsRepository
val readServiceStateFromRepository = settingsRepository.getServiceStateFromDataStore.asLiveData()

fun saveServiceState(state: Boolean): Job {
return viewModelScope.launch(Dispatchers.IO) {
settingsRepository.saveServiceStateToDataStore(state)
}
}
}

使用Messenger类与服务器通信https://developer.android.com/reference/android/app/Service.html#remote-messenger-service-sample

或者使用BroadcastReceiver从另一个进程获取服务状态

class MainActivity : AppCompatActivity() {
private var receiver: TmpReceiver? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.view_main)
val intent = Intent(this, TmpService::class.java)
receiver = TmpReceiver()
val filter = IntentFilter().apply {
addAction("SERVICE_START")
addAction("SERVICE_STOP")
}
registerReceiver(receiver, filter)
startService(intent)
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(receiver)
receiver = null
}
}
class TmpService : Service() {
override fun onBind(p0: Intent?): IBinder? {
return null
}
override fun onCreate() {
super.onCreate()
sendBroadcast("SERVICE_START")
}
override fun onDestroy() {
sendBroadcast("SERVICE_STOP")
super.onDestroy()
}
private fun sendBroadcast(action: String) {
Intent().also { intent ->
intent.action = action
sendBroadcast(intent)
}
}
}
class TmpReceiver: BroadcastReceiver() {
override fun onReceive(p0: Context?, p1: Intent?) {
Log.d("TmpReceiver", "action=${p1?.action}")
}
}

你可以在服务中再注册一个接收器,以便从活动中ping它。

关于最接近的答案,它只适用于单进程应用

最新更新