这是我的代码:
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)吗?
ViewModel
用于MVVM模式,其中ViewModel
忽略任何View类型的类,例如OnItemClickListener
,因此在将侦听器传递到ViewModel
工厂时会出现意外的用法。如果配置发生更改,这也会泄漏您的“片段”或“活动”。
甚至在ViewModel
中都没有使用侦听器,所以我看不到您,因此您可以完全消除此属性和工厂。您可以从AndroidViewModel
继承,并在构造函数中采用单个Context
参数。然后,您可以将by viewModels()
用于ViewModel
属性。
没有这些视图回调参数,没有什么可以限制您将所有这些都放在单个ViewModel
实现中。
您的视图模型具有返回其他ViewModel列表的功能也很奇怪。为什么这些只能是简单的数据类?不应直接实例化ViewModel(工厂实现除外)。否则,将无法管理其生命周期。