Android Compose、Viewmodel 和数据层以及服务

问题描述 投票:0回答:1

我开始进行 Android 开发,并且在 Compose 和

Viewmodel
方面遇到困难。

为了获得一些知识,我按照本教程获取了有关通过

ViewModel
和数据层与我的应用程序数据进行 UI 交互的基础知识: https://developer.android.com/codelabs/basic-android-kotlin-compose-viewmodel-and-state#0

对于一个基本的应用程序来说,这是可以的,现在我必须根据我的需求调整本教程,这些需求是: 一个将根据用户请求(UI 按钮)启动的应用程序 一个将在后台录制音频的前台服务(即使该应用程序是已关闭),并且录制状态和事件(由服务提供)应显示在 UI 中。服务部分已经开始工作,所以我需要一些有关 UI 交互的支持。

所以我的问题:

  1. 从哪里开始服务合适?在
    MainActivity
    ?在
    ViewModel
    (Viewmodel 缺乏启动服务的上下文)?
  2. 服务启动后,如何根据服务内部生成的事件(基于录制的音频)更新 UI?我正在考虑实现
    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

有什么帮助吗?

android android-jetpack-compose android-service android-viewmodel
1个回答
0
投票

在高层次上,您可以拥有一个服务用于推送事件的接口(或流程),您的活动将使用该接口(或流程)充当服务和 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)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.