使用MergeAdapter使适配器代码更清洁

厌倦了您的项目中过载和复杂的适配器,如下图所示?每次添加新的单元格类型时,是否要重写RecyclerView的适配器以使代码更易于阅读?有很多方法,通常建议使用委托适配器方法,例如,一个用于动态创建具有不同类型的视图(如groupie)的列表的库,您可以在本文中对其进行熟悉。但是今天,我们将讨论一个新类,该类将帮助封装适配器针对不同单元的逻辑,从而符合SOLID原则。



图片



MergeAdapterrecyclerview中引入的新类:1.2.0-alpha02,使您可以将多个显示适配器组合到一个RecyclerView中。这将允许您封装适配器中每个单元的逻辑,并允许将来重用它。



问题



让我们从一个例子开始。假设我们有一个任务来显示具有两种数据类型的提要-带有描述的文本和图片。onCreateViewHolder 在最常见的情况下,该方法中的代码如下所示:



override fun onCreateViewHolder(
    parent: ViewGroup, viewType: Int
): RecyclerView.ViewHolder? {
    val holder: RecyclerView.ViewHolder
    val inflater = LayoutInflater.from(parent.context)
    when (viewType) {
        TEXT_VIEW_TYPE -> {
            holder = TextViewHolder(
                inflater.inflate(R.layout.text_item, parent, false)
            )
        }
        IMAGE_VIEW_TYPE -> {
            holder = ImageViewHolder(
                inflater.inflate(R.layout.image_item, parent, false),
                imageClickListener
            )
        }
        else -> {
            throw IllegalArgumentException(
                "Can't create view holder from view type $viewType"
            )
        }
    }
    return holder
}


为什么这么糟?此实现的缺点是违反了DRY和SOLID的原则(单一责任和开放封闭)。为了确保这一点,添加两个要求就足够了:输入一种新的数据类型(复选框)和另外一个磁带,其中仅包含复选框和图片。



我们面临一个选择-为第二个磁带使用相同的适配器还是创建一个新的适配器?无论我们选择哪种解决方案,我们都必须更改代码(大约是同一件事,但是在不同的地方)。必须添加新的VIEW_TYPE,ViewHolder和编辑方法:getItemViewType(), onCreateViewHolder() onBindViewHolder()



如果我们决定保留一个适配器,那么更改将在那里结束。但是,如果将来将具有新逻辑的新数据类型仅添加到第二个提要中,则第一个提要将具有额外的功能,并且尽管未更改,但也需要进行测试。



如果我们决定创建一个新的适配器,将会有很多重复的代码。



决断



新的MergeAdapter类允许您为不同类型的单元格组合不同的适配器。例如,一个非常常见的用例是在Feed中加载数据时显示微调框,如果突然发生加载错误,则在Feed末尾显示有错误的单元格。



图片



可以使用MergeAdapter来解决此问题,假设我们有3个适配器:




val firstAdapter: FirstAdapter = …
val secondAdapter: SecondAdapter = …
val thirdAdapter: ThirdAdapter = …val mergeAdapter = MergeAdapter(firstAdapter, secondAdapter, thirdAdapter)
recyclerView.adapter = mergeAdapter


RecyclerView将按传递给构造函数的顺序依次显示每个适配器的项。不同的适配器使您可以为列表中的不同单元格分隔逻辑。例如,如果您需要在列表中添加标题,则不需要在适配器中实现此逻辑(该逻辑负责显示列表中的主要内容),则可以将适配器用于不同类型的单元格。这种方法有助于封装逻辑并在将来用于不同的屏幕。



图片



在标题的顶部或列表的底部显示下载内容。



要在列表的顶部或底部显示下载状态,您需要分别添加适配器:



val mergeAdapter = MergeAdapter(headerAdapter, listAdapter, footerAdapter)
recyclerView.adapter = mergeAdapter


顶部的单元格和底部的单元格使用相同的布局,ViewHolder和UI逻辑(显示加载状态和隐藏)。通常,对于列表的顶部和底部,使用同一适配器的2个实例就足够了。可以在此处此处找到示例



简而言之,如果您将复杂的适配器与不同类型的单元格一起使用,则可以通过这种简单的方法来改进项目的代码。



你喜欢这篇文章吗?不要忘记在TelegramAndroidSchool.ru平台上加入我们为Android开发人员提供有用的材料和现代教程。



All Articles