android - 用特定于UI的数据增强PagedList且不破坏MVVM模式的最佳方法

标签 android mvvm android-mvvm

我是MVVM模式的新手,但我真的很喜欢PagedList如何简化存储库中分页数据的使用。
但是现在我有以下情况:

  • 我的存储库具有如下方法:fun getLibraryItems(): LiveData<PagedList<ItemInfo>>

  • 其中ItemInfo是存储库特定的,并且不“了解” UI。
  • 接下来,我想使用UI特定数据(映射到另一个ui数据对象)来“增强”该数据对象,我只能从上下文感知的组件(例如这是Drawable资源。

  • 但是,如果需要的话,我无法直接从PagedList<X>映射到另一个PagedList<Y>-我需要更新数据源以接受“映射器”功能,如下所示:
    fun <T> getLibraryItems(mapper: (ItemInfo) -> T): LiveData<PagedList<T>> {
            return dataSource
                .getLibraryItems()
                .map(mapper)
                .toLiveData()
    }
    
    这样,我可以将ItemInfo映射到特定于UI的UI类型T,但是我无法在ViewModel中做到这一点,因为(据我所知)在ViewModel中加载Drawable资源是反模式。
    我不知道如何以及在何处将其称为“映射器”,应该是“ Activity ”/“片段”,还是我错过了smth和过于复杂的事物。

    最佳答案

    我认为有可能按照您的建议在ViewModel内映射数据,但与其在此处加载Drawable资源,不如仅传递其标识符。然后在您的UI层(RecyclerView Adapter,Activity或其他)中,通过其标识符加载资源。这样,您就不必在ViewModel中处理特定于上下文的方法。另外,如果您不想处理android资源ID(例如R.drawable.my_image),则必须保留自己的ID系统,然后将其映射到UI层内的android资源ID,尽管我个人认为这是多余的并发症。

    编辑:重新阅读您的问题后,我发现我的帖子没有完全回答它,所以这里有更多关于体系结构的内容:
    由于您要将域对象映射到特定于UI的对象,因此在ViewModel中这样做不是最佳实践,而不是clean architecture方式,这是正确的。因此正确的方法是在显示对象之前在UI层中进行此类映射。由于您使用PagedList,因此我可以假设您的RecyclerView适配器扩展了PagedListAdapter。然后,您可以创建抽象以支持适配器内部的映射。

    abstract class MyPagedAdapter<T, R, VH: RecyclerView.ViewHolder>(
        val dataMapper: (T)->R, 
        diffCallback: DiffUtil.ItemCallback<T>
    ): PagedListAdapter<T, VH>(diffCallback) {
        fun getMappedItem(position: Int) = dataMapper.invoke(getItem(position))
    }
    
    
    class LibraryItemAdapter(
        dataMapper: (LibraryItem)->UILibraryItem,
    ): MyPagedAdapter<LibraryItem, UILibraryItem, ViewHolderType>(dataMapper, /* provide diff callback here */) {
        /* implement onCreateViewHolder and getItemViewType here */
    
        override fun onBindViewHolder(holder: ViewHolderType, position: Int) {
            val item = getMappedItem(position)
            // configure view holder to display selected item
        }
     
    }
    
    
    // Then inside your fragment/activity:
    val mapper: (LibraryItem) -> UILibraryItem = { /* use your context-aware components to create an object for UI */ }
    recyclerView.adapter = LibraryItemAdapter(mapper)
    
    PS:我还想强调一点,将您的ViewModel/Repository/elsewhere中的整个列表映射到另一个包含Drawable,Bitmap或任何其他大型结构的类是一个坏主意,您最终可能会用Drawables淹没内存现在甚至不会显示。仅在要使用可绘制对象且不将其存储在列表中时才获取它们。我最初的答案和后来的修改都使您无法这样做
    P.P.S .:不要在您的映射器中进行过多的工作,因为当用户快速滚动大列表时,它可能会大量加载UI线程。在域/存储库层中执行所有业务逻辑。

    关于android - 用特定于UI的数据增强PagedList且不破坏MVVM模式的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65740094/

    相关文章:

    c# - 在 WPF 中同步 ViewModel

    android - 数据绑定(bind) Recyclerview 和 onClick

    C# WPF - 绑定(bind)到 DataGrid 中的父 ViewModel 不起作用

    android - 如何从协程返回异步操作到 ViewModel

    android - MVVM - 很难理解如何在 Clean Architecture 中创建域层

    android - 使用 picasso 库获取图像宽度和高度

    java - OTP 未从 firebase 代码中获取是正确的

    android - Android 浏览器中的溢出隐藏、边界半径和变换

    android - 始终在 ActionBar 中显示完整标题

    wpf - 如何将自定义排序规则应用于 WPF DataGrid?