我可以使用一个视图模型代替两个视图模型吗?

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

这是我的代码:

class AboutAdapter(private val clickListener: OnItemClickListener?) : AbstractListAdapter() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AboutItemViewHolder {
        val binding: AboutBinding = DataBindingUtil
            .inflate(
                LayoutInflater.from(parent.context), R.layout.view_item_about,
                parent, false
            )
        return AboutItemViewHolder(binding = binding)
    }

    override fun onBindHolder(holder: RecyclerView.ViewHolder, position: Int, item: Any) {
        (holder as AboutItemViewHolder).bind(item as SettingsItemViewModel, listener = clickListener)
    }
}

我的AboutFragment:

class AboutFragment : BaseFragment() {

    private lateinit var viewModel: AboutViewModel
    private lateinit var viewModelFactory: AboutViewModelFactory
    private var onItemClickListener: OnItemClickListener = object : OnItemClickListener {
        override fun onItemClick(titleName: Int) {
            when (titleName) {
                R.string.about_terms_service -> {
                    activity?.addFragment(WebViewFragment.newInstance(TERMS_LINK, getString(R.string.about_terms_service)))
                }
                R.string.about_open_source_licenses -> activity?.addFragment(LicensesFragment())
            }
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {

        viewModelFactory = AboutViewModelFactory(requireContext(), onItemClickListener)
        viewModel = ViewModelProviders.of(this, viewModelFactory)
            .get(AboutViewModel::class.java)

        return inflater.inflate(R.layout.fragment_base_list, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        activityComponents?.updateAppbarTitleWithFabAction(getString(R.string.about_feature_title))
        setupViews()
    }

    private fun setupViews() {
        try {
            val layoutManager = LinearLayoutManager(activity)
            recyclerView?.layoutManager = layoutManager
            val dividerItemDecoration = DividerItemDecoration(context, layoutManager.orientation)
            ContextCompat.getDrawable(context ?: return, R.drawable.shape_full_divider)?.let {
                dividerItemDecoration.setDrawable(it)
            }
            recyclerView?.addItemDecoration(dividerItemDecoration)
            recyclerView?.adapter = AboutAdapter(viewModel.onItemClickListener).apply {
                data = viewModel.getListItems()
            }
        } catch (e: Exception) {
            e.log()
        }
    }
}

我的AboutItemViewHolder:

class AboutItemViewHolder(
    binding: AboutBinding
) : RecyclerView.ViewHolder(binding.root){

    private var aboutBinding: AboutBinding? = null

    init {
        this.aboutBinding = binding
    }

    fun bind(item: SettingsItemViewModel, listener: OnItemClickListener?) {
        aboutBinding?.about = AboutListItemViewModel(item)
        aboutBinding?.onItemClickListener = listener
        aboutBinding?.executePendingBindings()
    }
}

interface OnItemClickListener {
    fun onItemClick(titleName: Int)
}

我在适配器AboutListItemViewModel中使用的第一个ViewModel:

class AboutListItemViewModel(item: SettingsItemViewModel) {

    val titleName: Int = item.titleId
    val subTitleName: String? = item.value
    var isVisible: Boolean = item.value != null
}

我在片段AboutViewModel中使用的第二个ViewModel:

class AboutViewModel(val appContext: Context, val onItemClickListener: OnItemClickListener): ViewModel() {

    fun getListItems(): List<SettingsItemViewModel> {
        return listOf(
            SettingsItemViewModel(
                titleId = R.string.about_app_version,
                value = AppTools.getAppVersionName(appContext)
            ),
            SettingsItemViewModel(
                titleId = R.string.about_copyright,
                value = appContext.getString(R.string.about_copyright_description)
            ),
            SettingsItemViewModel(
                titleId = R.string.about_terms_service,
                itemIsClickable = true
            ),
            SettingsItemViewModel(
                titleId = R.string.about_open_source_licenses,
                itemIsClickable = true
            )
        )
    }
}

我的AboutViewModelFactory:

class AboutViewModelFactory(val appContext: Context, private val onItemClickListener: OnItemClickListener) : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(AboutViewModel::class.java)) {
            return AboutViewModel(appContext, onItemClickListener) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

SettingsViewModel是简单的数据类:

data class SettingsItemViewModel(
    @StringRes val titleId: Int,
    val value: String? = null,
    val switchEnabled: Boolean? = null,
    val isChecked: Boolean = false,
    val itemIsClickable: Boolean = false,
    val colorResId: Int = R.color.black
)

Q:我可以使用一个ViewModel代替我的两个视图模型(AboutViewModel和AboutListItemViewModel)吗?

android kotlin mvvm android-viewmodel
1个回答
0
投票

ViewModel用于MVVM模式,其中ViewModel忽略任何View类型的类,例如OnItemClickListener,因此在将侦听器传递到ViewModel工厂时会出现意外的用法。如果配置发生更改,这也会泄漏您的“片段”或“活动”。

甚至在ViewModel中都没有使用侦听器,所以我看不到您,因此您可以完全消除此属性和工厂。您可以从AndroidViewModel继承,并在构造函数中采用单个Context参数。然后,您可以将by viewModels()用于ViewModel属性。

没有这些视图回调参数,没有什么可以限制您将所有这些都放在单个ViewModel实现中。

您的视图模型具有返回其他ViewModel列表的功能也很奇怪。为什么这些只能是简单的数据类?不应直接实例化ViewModel(工厂实现除外)。否则,将无法管理其生命周期。

© www.soinside.com 2019 - 2024. All rights reserved.