我想制作一个垂直RecyclerView
和嵌套水平RecyclerView
s的应用程序。我不知道在这种情况下如何正确使用mvp模式。mvp的“规则”说,一个屏幕应该只有一个视图。
MyView
界面:
public interface ViewLayer {
void showProductsInCategory(int categoryId, List<ProductModel> productList, PresenterLayer presenter);
void showCategories(List<CategoryModel> categoryItemList, PresenterLayer presenter);
}
节目主持人:
public interface PresenterLayer {
void onViewReady();
}
型号:
public interface InteractorLayer {
void getProducts(int categoryId);
void getCategories();
}
模型侦听器接口:
public interface InteractorListener {
void onProductsLoaded(int id, List<ProductModel> products);
void onCategoriesLoaded(List<CategoryModel> categories);
}
分类模型:
public class CategoryModel {
private String categoryName;
private List<ProductModel> productList;
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public List<ProductModel> getProductList() {
return productList;
}
public void setProductList(List<ProductModel> productList) {
this.productList = productList;
}
}
所以我必须通过选择每个嵌套的
RecyclerView
来将数据添加到它们的适配器中。我可以为每个水平categoryId
创建单独的模型视图演示程序接口吗?升级版:
一步一步地
1)
RecyclerView
呼叫MainActivity.onCreate
2)演示者呼叫
presenter.onViewReady()
3)模型调用
interactorLayer.getCategories()
4)演示者呼叫
InteractorListener.onCategoriesLoaded(List<CategoryModel> categories)
(ViewLayer
)MainActivity
5)
showCategories(List<CategoryModel> categoryItemList, PresenterLayer presenter)
将其设置为外部适配器。现在每个分类项都有MainActivity
categoryItemList
6)在
RecyclerView
方法中,在null
之后,演示者在每个类别的循环中调用模型的productList
。7)在任何
onCategoriesLoaded(...)
加载ViewLayer.showCategories(...)
调用InteractorLayer.getProducts(i)
后8)
productList
获取主Presenter
的ViewLayer
,获取类别项并为其设置showProductsInCategory(...)
。9)呼叫
10)当
MainActivity
调用时,内部Adapter
设置新的RecyclerView
。我觉得很复杂。我该怎么办?
UPD 2017年3月24日
源代码:https://github.com/Lex74/ProductsShop
最佳答案
首先,我想说的是,我不认为自己是一个MVP大师,而是一个努力理解模式的人,
我最喜欢的MVP推荐人:The Clean Architecture来自Bob叔叔的博客
根据这篇博文,有一个叫做依赖规则的东西:
…源代码依赖项只能指向内部。一个内圈的任何东西都不可能知道外圈的任何东西…
例如,Presenter
类不需要知道任何关于RecyclerView
或RecyclerView.Adapter
的信息。它需要一些interface
来将信息传递到外层。interface
的方法取决于用例:使用List
,人们希望能够
传递对整个数据的引用List
(showCategories()
)
刷新单个列表项(showProductsInCategory()
)
所以我认为依赖规则说,ViewLayer
接口必须提供满足[model层和]presenter层需要的方法。作为一个演讲者,我根本不在乎外面的景色是不是有一个ListView
或者根本不是一个View
而是一些声音和振动信号的组合。
另一方面,对于View
类来说,知道其Presenter
类的名称(和方法)似乎是完全可以的,因此PresenterLayer
接口可能不是必需的。
这完全取决于如何向用户提供数据。嵌套结构仍然是一个复杂的结构。所以我认为不需要提供嵌套的。
在某些嵌套View
s的情况下,View
可能需要一种方法来更新内部interface
的项,类似于List
。
另一个有趣的问题是:谁保存(并可能修改)数据?在我看来,演示者负责数据,它应该只将对数据的引用传递到视图层或通知它更改。适配器不应该有权修改原始数据列表,演示者不应该问适配器“有多少项?”我不太喜欢两个独立的数据列表。各种通知的名字…方法似乎表明我在正确的轨道上。
这意味着Presenter
将始终保持原始数据List
。如果数据发生变化,showSingleProductInCategory(ProductModel product, int categoryPosition, int productPosition)
将更新其数据(可能是Presenter
和“复制新项”,也可能更细粒度,具体取决于List
提供的内容),然后,Presenter
将通过clear()
接口通知ProductLoader
。
链接到azip file with the modified Java classes
编辑
不知怎的,我怀疑“一个屏幕一个视图”是否适合android。想象一下典型的主细节情况。如果屏幕很大,则需要使用该空间并同时显示两个Presenter
s。
因此,如果每个Adapter
有一个视图(和一个演示者),那么所有类型的屏幕都可以使用。根据屏幕大小,由ViewLayer
来管理Fragment
s。
我已经解释过,我喜欢让一些Fragment
或Activity
的Fragment
实现Adapter
,这是ListView
回调所必需的。(作为回调函数的所有RecyclerView
都可以将信息传递给interface
)
另一方面,aPresenter
可能包含多组数据。其中一些可能有某种关联(就像某个艺术家的所有歌曲),而其他的(所有那些广告…)则不然。演示者需要一些方法来告诉视图要向用户显示什么:一种方法用于艺术家,一种方法用于广告等。
因此,如果我有一个带有少量Fragment
s的应用程序,Adapter
将包含如下方法
void showAdvertisement(AdObject ad);
void showArtistInfo(Artist artist);
…而
Fragment
将期望某个类在其Fragment
中实现这个特定的interface
。(加上歌曲的Presenter
),我会让interface
实现所有非采集数据的Constructor
。在一个有多个应用程序的项目中,可以考虑使用generic
Adapter
s(一个用于任何类型的详细信息,一个用于集合)。然后将有一个方法
Fragment
,上面示例中的interface
将需要一个广告回调和一个艺术家信息回调:MyPlaylistPresenter (DetailInterface<AdObject> adCallback, DetailInterface<Artist> artistCallback, CollectionInterface<Song> songsCallback){...}
然后在
interface
中会写下:MyPlaylistPresenter presenter = new MyPlaylistPresenter(this, this, adapter);
有点像乐高(lego:),但所有的课程都比较少。基本上做相同事情的方法在整个项目中都有相同的名称,所以我认为它有助于维护性。
关于你的另一个问题:
如果你的应用程序在客户端有一个模型,那么我认为你是对的。
另一方面,有些项目的模型是后端的一部分。那么演讲者就是合乎逻辑的选择。
关于android - 嵌套的RecyclerViews MVP实现,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42889594/