- 背景**
因此,我一直在为几个项目使用MVVM架构。我仍然在尝试找出和改进架构的工作方式。我一直在使用MVP架构,使用常用的工具集Dagger for DI,通常是多模块项目,Presenter层被注入了一堆交互器/用例,每个交互器被注入了不同的存储库来执行后端API调用。
现在我已经进入MVVM,我通过ViewModel更改了Presenter层,从ViewModel到UI层的通信是通过LiveData完成的,而不是使用View回调接口,等等。
看起来像这样:
class ProductDetailViewModel @inject constructor(
private val getProductsUseCase: GetProductsUseCase,
private val getUserInfoUseCase: GetUserInfoUseCase,
) : ViewModel(), GetProductsUseCase.Callback, GetUserInfoUseCase.Callback {
// Sealed class used to represent the state of the ViewModel
sealed class ProductDetailViewState {
data class UserInfoFetched(
val userInfo: UserInfo
) : ProductDetailViewState(),
data class ProductListFetched(
val products: List<Product>
) : ProductDetailViewState(),
object ErrorFetchingInfo : ProductDetailViewState()
object LoadingInfo : ProductDetailViewState()
}
...
// Live data to communicate back with the UI layer
val state = MutableLiveData<ProductDetailViewState>()
...
// region Implementation of the UseCases callbacks
override fun onSuccessfullyFetchedProducts(products: List<Product>) {
state.value = ProductDetailViewState.ProductListFetched(products)
}
override fun onErrorFetchingProducts(e: Exception) {
state.value = ProductDetailViewState.ErrorFetchingInfo
}
override fun onSuccessfullyFetchedUserInfo(userInfo: UserInfo) {
state.value = ProductDetailViewState.UserInfoFetched(userInfo)
}
override fun onErrorFetchingUserInfo(e: Exception) {
state.value = ProductDetailViewState.ErrorFetchingInfo
}
// Functions to call the UseCases from the UI layer
fun fetchUserProductInfo() {
state.value = ProductDetailViewState.LoadingInfo
getProductsUseCase.execute(this)
getUserInfoUseCase.execute(this)
}
}
这里没有火箭科学,有时我改变实现使用多个LiveData属性来跟踪变化。顺便说一句,这只是我在运行中编写的一个示例,所以不要指望它能编译。但事实就是这样,ViewModel被注入了一堆用例,它实现了UseCases回调接口,当我从UseCases获得结果时,我通过LiveData将其传递给UI层。
我的用例通常是这样的:
// UseCase interface
interface GetProductsUseCase {
interface Callback {
fun onSuccessfullyFetchedProducts(products: List<Product>)
fun onErrorFetchingProducts(e: Exception)
}
fun execute(callback: Callback)
}
// Actual implementation
class GetProductsUseCaseImpl(
private val productRepository: ApiProductRepostory
) : GetProductsUseCase {
override fun execute(callback: Callback) {
productRepository.fetchProducts() // Fetches the products from the backend through Retrofit
.subscribe(
{
// onNext()
callback.onSuccessfullyFetchedProducts(it)
},
{
// onError()
callback.onErrorFetchingProducts(it)
}
)
}
}
我的Repository类通常是Retrofit示例的 Package 器,它们负责设置适当的Scheduler,以便所有内容都在适当的线程上运行,并将后端响应Map到模型类。后端响应是指与GsonMap的类(例如ApiProductResponse列表),它们被Map到模型类(例如我在整个应用程序中使用的产品列表)
- 问题**
我在这里的问题是,自从我开始使用MVVM体系结构以来,所有的文章和所有的示例,人们要么将存储库直接注入到视图模型中(复制代码以处理错误并Map响应)或使用单一真实数据源模式(使用Room的Flowables从Room中获取信息)但是我还没有看到任何人使用带有ViewModel层的用例,我的意思是它非常方便,我把事情分开,我在用例中Map后端响应,我处理那里的任何错误。但是,我仍然觉得我没有看到任何人在做这件事,* * 是否有一些方法可以改进用例,使它们在API方面对视图模型更友好?使用回调接口以外的其他接口执行用例和视图模型之间的通信?**
请让我知道,如果你需要任何更多的信息,这一点。对不起的例子,我知道这些不是最好的,我只是出来了一些简单的为了更好地解释它。
谢谢你,
- 编辑#1**
下面是我的Repository类的外观:
// ApiProductRepository interface
interface ApiProductRepository {
fun fetchProducts(): Single<NetworkResponse<List<ApiProductResponse>>>
}
// Actual implementation
class ApiProductRepositoryImpl(
private val retrofitApi: ApiProducts, // This is a Retrofit API interface
private val uiScheduler: Scheduler, // AndroidSchedulers.mainThread()
private val backgroundScheduler: Scheduler, // Schedulers.io()
) : GetProductsUseCase {
override fun fetchProducts(): Single<NetworkResponse<List<ApiProductResponse>>> {
return retrofitApi.fetchProducts() // Does the API call using the Retrofit interface. I've the RxAdapter set.
.wrapOnNetworkResponse() // Extended function that converts the Retrofit's Response object into a NetworkResponse class
.observeOn(uiScheduler)
.subscribeOn(backgroundScheduler)
}
}
// The network response class is a class that just carries the Retrofit's Response class status code
3条答案
按热度按时间rryofs0p1#
更新用例,使其返回
Single<List<Product>>
:然后,更新您的
ViewModel
,使其订阅产品流:有一件事我忽略了,那就是
List<ApiProductResponse>>
到List<Product>
的适配,但是这可以通过用helper函数Map列表来处理。at0kjp5o2#
我最近的两个项目刚刚开始使用MVVM。我可以和你分享我在ViewModel中处理REST API的过程。希望它能帮助你和其他人。
我希望这种方法可以帮助您减少一些样板代码。
cfh9epnr3#
当我不久前开始使用MVVM时,我也有同样的问题。我基于Kotlin挂起函数和协程,提出了以下解决方案:
1.将ApiProductRepositoryImpl.fetchProducts()更改为同步运行。为此,请更改改进接口以返回Call<...>,然后将存储库实现更改为
1.让您的用例实现以下接口:
因此,您GetProductsUseCase看起来应该是这样的:
1.在ViewModel中执行用例
有关更多信息和示例,请参见https://github.com/snellen/umvvm。