您好,欢迎来到华佗养生网。
搜索
您的当前位置:首页Compose的MVVM架构示例

Compose的MVVM架构示例

来源:华佗养生网

最近在学习Compose的过程中,参考MVVM对整体框架进行了封装,分为BaseActivity、BaseViewModel,通过继承和反射的方式,完成对ViewModel的创建和绑定。以下给出示例:

BaseViewModel

采用实现接口的方式,完成对BaseViewModel的定义。优势:提高代码的安全性、灵活性和适用性。

// ViewModel的定义
interface IViewModel<out ViewModel : BaseViewModel> {
    val mViewModel: ViewModel
}

封装BaseViewModel,可以实现公用的方法,比如网络请求时的转圈效果:

abstract class BaseViewModel : ViewModel() {

    private val _isLoading = MutableStateFlow(false)
    val isLoading: StateFlow<Boolean> = _isLoading

    protected fun setLoading(isLoading: Boolean) {
        _isLoading.value = isLoading
    }

    protected fun handleError(exception: Exception) {
        Log.e(TAG, "$exception")
    }

    companion object {
        private const val TAG = "BaseViewModel"
    }

}

BaseActivity

  • 使用反射的方式传入ViewModel

  • 使用遍历继承链的方式实例化mViewModel变量

  • 这样在子类中就可以通过mViewModel调用相关的ViewModel获取数据

  • 通过抽象方法的方式传入Composable方法

  PS:不将Composable方法作为类的构造参数传入的原因是,可能我们在Composable方法调用的一些系统API需要使用Context,而Composable方法作为构造参数传入由于Activity生命周期未到onCreate,无法获取到Context,所以将Composable方法定义为抽象方法,由子类实现。

abstract class BaseActivity<out ViewModel : BaseViewModel> : ComponentActivity(),
    IViewModel<ViewModel> {

    final override val mViewModel: ViewModel

    init {
        mViewModel = findViewModelClass().newInstance()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            MyComposeDemoTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    ScreenContent()
                }
            }
        }
    }

    @Suppress("UNCHECKED_CAST")
    private fun findViewModelClass(): Class<ViewModel> {
        var thisClass: Class<*> = this.javaClass
        while (true) {
            (thisClass.genericSuperclass as? ParameterizedType)?.actualTypeArguments?.firstOrNull()
                ?.let {
                    return it as Class<ViewModel>
                }
                ?: run {
                    thisClass = thisClass.superclass ?: throw IllegalArgumentException()
                }
        }
    }

    @Composable
    abstract fun ScreenContent()

}

使用示例

// MainActivity
class MainActivity : BaseActivity<MainViewModel>() {

    @Composable
    override fun ScreenContent() = ScrollableButtonColum(mViewModel)

}

@Composable
private fun ScrollableButtonColum(viewModel: MainViewModel) {
    val context = LocalContext.current
    val scrollState = rememberScrollState()
    Column(modifier = Modifier.verticalScroll(scrollState)) {
        viewModel.buttons.forEach { buttonText ->
            Button(
                onClick = {
                    with(context) {
                        when (buttonText) {
                            MainViewModel.FLASH_LIGHT -> jumpTo<FlashlightActivity>()

                            MainViewModel.ANIMATION_OFFSET -> jumpTo<AnimationOffsetActivity>()

                            MainViewModel.TAB_PAGER -> jumpTo<TabActivity>()

                            MainViewModel.SCRAPE_CARD -> jumpTo<ScratchCardActivity>()
                        }
                    }
                },
                modifier = Modifier.padding(8.dp)
            ) {
                Text(text = buttonText)
            }
        }
    }
}

// MainViewModel
class MainViewModel : BaseViewModel() {

    val buttons: List<String> by lazy {
        listOf(
            FLASH_LIGHT, ANIMATION_OFFSET, TAB_PAGER, SCRAPE_CARD
        )
    }

    companion object {
        const val FLASH_LIGHT = "手电筒"
        const val ANIMATION_OFFSET = "动画偏移"
        const val TAB_PAGER = "首页模拟"
        const val SCRAPE_CARD = "刮刮乐"
    }

}

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- huatuo7.cn 版权所有 湘ICP备2022005869号-9

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务