0

我从一个service不同的地方开始。设计为即使在应用程序关闭时也能运行。从 开始后,我关闭了应用程序。现在,当我重新打开应用程序时,可能会或可能不会运行。但我还没有找到方法来知道它是否正在运行。我怎样才能做到这一点?processactivityserviceserviceactivityserviceservice

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

这是我目前正在做的事情:

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(目的:将服务的运行状态保存在 Preference DataStore 中)

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)
       }
   }
}
4

1 回答 1

0

使用 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 操作。

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

于 2021-03-11T07:38:05.100 回答