我开始进行 Android 开发,并且在 Compose 和
Viewmodel
方面遇到困难。
为了获得一些知识,我按照本教程获取了有关通过
ViewModel
和数据层与我的应用程序数据进行 UI 交互的基础知识:
https://developer.android.com/codelabs/basic-android-kotlin-compose-viewmodel-and-state#0
对于一个基本的应用程序来说,这是可以的,现在我必须根据我的需求调整本教程,这些需求是: 一个将根据用户请求(UI 按钮)启动的应用程序 一个将在后台录制音频的前台服务(即使该应用程序是已关闭),并且录制状态和事件(由服务提供)应显示在 UI 中。服务部分已经开始工作,所以我需要一些有关 UI 交互的支持。
所以我的问题:
MainActivity
?在ViewModel
(Viewmodel 缺乏启动服务的上下文)?LocalBroadcastManager
并在我的 ViewModel
实现中监听服务中生成的事件,但我发现 LocalBroadcastManageris
已弃用。这是我的 ViewModel 和数据层代码:
class ServiceView(): ViewModel() {
data class ServiceViewData(
var isStarted:Boolean = false,
var isCapturing:Boolean = false,
var isPlaying:Boolean = false,
var isAutoPlaying:Boolean = false,
)
var serviceViewData by mutableStateOf(ServiceViewData())
fun startService(){
// Start the service here?
serviceViewData = serviceViewData.copy(isStarted = true)
}
}
关于 UI,它将根据我的
ServiceViewData
ServiceView
中定义的 ViewModel
数据层的值组成,因此来自我的服务的事件应该以某种方式在 ViewModel
中接收,以便修改我的 ServiceViewData
。
有什么帮助吗?
在高层次上,您可以拥有一个服务用于推送事件的接口(或流程),您的活动将使用该接口(或流程)充当服务和 ViewModel 之间的中介。您的活动还像往常一样观察虚拟机并更新 UI,无论是 Compose 还是 Views。
活动 -> 观察 -> 服务 -> 然后更新 -> ViewModel
Activity -> 观察 -> ViewModel -> 然后更新 -> UI
因此您的服务可能类似于:
class YourService : Service {
data class ServiceEventParams(...)
interface EventListener {
fun onSomeServiceEvent()
}
val eventListener: EventListener? = null // Or a flow of params
fun functionThatWantsToPropogateEvents() {
// DO STUFF then notify any listener that stuff happened
val params = ServiceEventParams(...)
eventListener?.onSomeServiceEvent(params)
}
}
使用文档中的示例,您的活动可能如下所示:
class BindingActivity : Activity() {
private lateinit var mService: LocalService
private var mBound: Boolean = false
private val mViewModel = getViewModelSomehow() // <- NEW
// NEW - listener for service events
private val mServiceEventListener = object : YourService.EventListener {
override fun onSomeServiceEvent(params: ServiceEventParams) {
mViewModel.doSomethingToRespondToServiceEvent(params)
}
}
/** Defines callbacks for service binding, passed to bindService(). */
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
// We've bound to LocalService, cast the IBinder and get LocalService instance.
val binder = service as LocalService.LocalBinder
mService = binder.getService()
mBound = true
// NEW - register listener on the service to get callbacks
mService.setListener(mServiceEventListener)
// OR Collect a flow of events
}
override fun onServiceDisconnected(arg0: ComponentName) {
mBound = false
// NEW - clear out listener on the service to stop callbacks
mService.setListener(null)
// OR stop collecting a flow of events
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// NEW - initialize UI and observe ViewModel to update UI state
// whether it's Compose or Views
}
override fun onStart() {
super.onStart()
// Bind to LocalService.
Intent(this, LocalService::class.java).also { intent ->
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
}
override fun onStop() {
super.onStop()
unbindService(connection)
mBound = false
}
}
最后,您的视图模型只需要处理服务参数并转换为视图状态:
class ServiceViewModel : ViewModel {
fun doSomethingToRespondToServiceEvent(params: ServiceEventParams) {
serviceViewData = someFunctionThatMapsToViewState(params)
}
}