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()

}

使用示例

以下是一个使用上述MVVM进行实现的示例代码,相当于跳转目录。

// 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 = "刮刮乐"
    }

}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值