Android 存储库模式:如何将额外数据传递给 Fragment/Activity
Android repository pattern: how pass extra data to Fragment/Activity
我读了这篇指南:https://developer.android.com/jetpack/docs/guide
并尝试在这种情况下使用存储库模式:
app 通过 Retrofit lib 向服务器 /get/user
发出 GET 请求,服务器的响应可能是这样的(状态为 200):
{
"user": {"name" : "Jack", "id": "99"},
"status": true
}
或像这样(状态为 200):
{ "status": false, "message": "Some error here"}
或者,500 错误,例如。
我的 UserFragment
应该显示对话框,具体取决于服务器响应:如果一切正常 - 正常消息,如果状态为假 - 来自 api 响应的错误消息,如果 500 - 其他错误消息。
我的 POJO 模型如下所示:
public class User {
private String id;
private String name;
// getters and setters omitted
}
public class ApiResponse {
private User user;
private Boolean status;
private String message;
// getters and setters omitted
}
我应该如何在存储库模式中处理它?
- 我的存储库对象是否应该 return ViewModel 的用户?如果是 - 我的 ViewModel 如何知道 api 响应的状态和消息字段?
- 或者我的存储库对象应该 return 直接 ApiResponse 到 ViewModel,ViewModel 从中获取状态、消息和用户并将它们传递给 Fragment?但是如果我想将用户缓存到数据库怎么办?我们需要将所有 ApiResponse 存储到数据库还是只需要存储用户?
- 或者别的什么...?
我更喜欢 1,因为它对我来说更清晰,但我的问题 - 如何处理状态和消息字段,return从服务器编辑并需要在 Fragment 中显示数据。
这有点取决于您打算在 Fragment
上显示的信息。
如果网络出现问题,您会向用户显示错误消息吗?或者你会很高兴只显示一条 "user not found" 消息。
您计划向用户展示的数据应该进入 ViewModel
。
如果您打算直接显示来自 Api 的错误消息,请将其传递给 ViewModel
。
如果您打算只向用户显示,则将其传递给 ViewModel
。在这种情况下,错误消息只能概括。
使用改造,
你可以在 Callback Class,
中得到响应
你必须创建一个新的 class extends that,
class SampleCallback(private var mContext: Context) : Callback<SampleResponse> {
override fun onResponse(call: Call<SampleResponse>, response: Response<SampleResponse>) {
when (response.code()) {
200-> //Update your View with mContext
}
}
}
不要忘记覆盖 onFailure。
我是这样操作的:
存储库:
prival final MutableLiveData<User> userData = new MutableLiveData<>();
public void getUser(){
//post user to userData when you got response from the server
}
public LiveData<User> getUserData(){ return userData; }
视图模型:
public LiveData<User> user = Repository.getInstance().getUserData();
在这种情况下,您的 viewModel 不会每次都创建 liveData,它会从 Repository 中获取 liveData。此外,您将在您的存储库中加载数据,因此您不必经常触发调用。
如果您需要了解每个呼叫状态,请在 liveData 和 response obj livedata 中使用您的 NetworkState 枚举创建类似 DataSource holder 对象的对象
这是我的远程数据源:
public class RemoteDataSource<T> {
private final MutableLiveData<NetworkState> networkState = new MutableLiveData<>();
private final MutableLiveData<T> data = new MutableLiveData<>();
private final Action action;
private String errorMessage;
public RemoteDataSource(Action action) {
networkState.postValue(NetworkState.Default);
this.action = action;
}
public MutableLiveData<NetworkState> getNetworkState() {
return networkState;
}
public void setIsLoading() {
networkState.postValue(NetworkState.Loading);
}
public void setDefault() {
networkState.postValue(NetworkState.Default);
}
public void setIsLoaded(T data) {
networkState.postValue(NetworkState.Loaded);
this.data.postValue(data);
}
public void setFailed(@NonNull String errorMessage) {
this.errorMessage = errorMessage;
networkState.postValue(NetworkState.Failed);
}
public String getErrorMessage() {
return errorMessage;
}
public MutableLiveData<T> getData() {
return data;
}
public void executeLoad() {
if (action != null) {
try {
action.run();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
我使用存储库模式来保持简单的操作来检索所需的信息,没有什么很复杂的:
/**
* Repository that exposes DataSources and Observables for loading data from local/network sources
* Repository also exposes Subjects that inform about state of the calls
*/
class ExampleCitiesRepository @Inject constructor(private val apiCities: ExampleCitiesApiEndpointsInterface,
private val daoCities: ExampleCityDao) {
fun citiesDataSourceFactory(compositeDisposable: CompositeDisposable) = CitiesDataSourceFactory(apiCities, compositeDisposable)
fun citiesFromNetwork() =
apiCities.getCitiesList().mapResponseList(mapper = { ExampleCityModel(it) })
fun pagedCitiesFromDatabase() = daoCities.citiesPagedById().map { ExampleCityModel(it) }
fun citiesFromDatabase() = daoCities.citiesById().map { it.map { ExampleCityModel(it) } }!!
fun saveAllCitiesToDatabase(cities: Collection<ExampleCityModel>) = Single.fromCallable { daoCities.insertOrReplaceAll(cities.map { ExampleCityDbModel(it) }) }!!
fun deleteAllCitiesFromDatabase() = Single.fromCallable { daoCities.deleteAll() }!!
}
此外,我正在将 "Backend models" 映射到应用程序模型(我不喜欢创建一个模型,因为后端可以更改他们的模型,然后它会迫使我们也更改我们的模型)。就是这样,我可以获得我想要处理的模型,可以使用 Rx 的处置结束调用或使用它获取错误代码或消息。
ViewModels 与此配合得很好,因为我们可以在不再需要 viewModel 时获得回调,然后我们可以取消网络调用。如果应用程序未打开,我们可以继续进行网络调用,因为实时数据可以确保在正确的时间将数据从 ViewModel 传递到 View
我读了这篇指南:https://developer.android.com/jetpack/docs/guide
app 通过 Retrofit lib 向服务器 /get/user
发出 GET 请求,服务器的响应可能是这样的(状态为 200):
{
"user": {"name" : "Jack", "id": "99"},
"status": true
}
或像这样(状态为 200):
{ "status": false, "message": "Some error here"}
或者,500 错误,例如。
我的 UserFragment
应该显示对话框,具体取决于服务器响应:如果一切正常 - 正常消息,如果状态为假 - 来自 api 响应的错误消息,如果 500 - 其他错误消息。
我的 POJO 模型如下所示:
public class User {
private String id;
private String name;
// getters and setters omitted
}
public class ApiResponse {
private User user;
private Boolean status;
private String message;
// getters and setters omitted
}
我应该如何在存储库模式中处理它?
- 我的存储库对象是否应该 return ViewModel 的用户?如果是 - 我的 ViewModel 如何知道 api 响应的状态和消息字段?
- 或者我的存储库对象应该 return 直接 ApiResponse 到 ViewModel,ViewModel 从中获取状态、消息和用户并将它们传递给 Fragment?但是如果我想将用户缓存到数据库怎么办?我们需要将所有 ApiResponse 存储到数据库还是只需要存储用户?
- 或者别的什么...?
我更喜欢 1,因为它对我来说更清晰,但我的问题 - 如何处理状态和消息字段,return从服务器编辑并需要在 Fragment 中显示数据。
这有点取决于您打算在 Fragment
上显示的信息。
如果网络出现问题,您会向用户显示错误消息吗?或者你会很高兴只显示一条 "user not found" 消息。
您计划向用户展示的数据应该进入 ViewModel
。
如果您打算直接显示来自 Api 的错误消息,请将其传递给 ViewModel
。
如果您打算只向用户显示,则将其传递给 ViewModel
。在这种情况下,错误消息只能概括。
使用改造,
你可以在 Callback Class,
中得到响应
你必须创建一个新的 class extends that,
class SampleCallback(private var mContext: Context) : Callback<SampleResponse> {
override fun onResponse(call: Call<SampleResponse>, response: Response<SampleResponse>) {
when (response.code()) {
200-> //Update your View with mContext
}
}
}
不要忘记覆盖 onFailure。
我是这样操作的:
存储库:
prival final MutableLiveData<User> userData = new MutableLiveData<>();
public void getUser(){
//post user to userData when you got response from the server
}
public LiveData<User> getUserData(){ return userData; }
视图模型:
public LiveData<User> user = Repository.getInstance().getUserData();
在这种情况下,您的 viewModel 不会每次都创建 liveData,它会从 Repository 中获取 liveData。此外,您将在您的存储库中加载数据,因此您不必经常触发调用。
如果您需要了解每个呼叫状态,请在 liveData 和 response obj livedata 中使用您的 NetworkState 枚举创建类似 DataSource holder 对象的对象
这是我的远程数据源:
public class RemoteDataSource<T> {
private final MutableLiveData<NetworkState> networkState = new MutableLiveData<>();
private final MutableLiveData<T> data = new MutableLiveData<>();
private final Action action;
private String errorMessage;
public RemoteDataSource(Action action) {
networkState.postValue(NetworkState.Default);
this.action = action;
}
public MutableLiveData<NetworkState> getNetworkState() {
return networkState;
}
public void setIsLoading() {
networkState.postValue(NetworkState.Loading);
}
public void setDefault() {
networkState.postValue(NetworkState.Default);
}
public void setIsLoaded(T data) {
networkState.postValue(NetworkState.Loaded);
this.data.postValue(data);
}
public void setFailed(@NonNull String errorMessage) {
this.errorMessage = errorMessage;
networkState.postValue(NetworkState.Failed);
}
public String getErrorMessage() {
return errorMessage;
}
public MutableLiveData<T> getData() {
return data;
}
public void executeLoad() {
if (action != null) {
try {
action.run();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
我使用存储库模式来保持简单的操作来检索所需的信息,没有什么很复杂的:
/**
* Repository that exposes DataSources and Observables for loading data from local/network sources
* Repository also exposes Subjects that inform about state of the calls
*/
class ExampleCitiesRepository @Inject constructor(private val apiCities: ExampleCitiesApiEndpointsInterface,
private val daoCities: ExampleCityDao) {
fun citiesDataSourceFactory(compositeDisposable: CompositeDisposable) = CitiesDataSourceFactory(apiCities, compositeDisposable)
fun citiesFromNetwork() =
apiCities.getCitiesList().mapResponseList(mapper = { ExampleCityModel(it) })
fun pagedCitiesFromDatabase() = daoCities.citiesPagedById().map { ExampleCityModel(it) }
fun citiesFromDatabase() = daoCities.citiesById().map { it.map { ExampleCityModel(it) } }!!
fun saveAllCitiesToDatabase(cities: Collection<ExampleCityModel>) = Single.fromCallable { daoCities.insertOrReplaceAll(cities.map { ExampleCityDbModel(it) }) }!!
fun deleteAllCitiesFromDatabase() = Single.fromCallable { daoCities.deleteAll() }!!
}
此外,我正在将 "Backend models" 映射到应用程序模型(我不喜欢创建一个模型,因为后端可以更改他们的模型,然后它会迫使我们也更改我们的模型)。就是这样,我可以获得我想要处理的模型,可以使用 Rx 的处置结束调用或使用它获取错误代码或消息。
ViewModels 与此配合得很好,因为我们可以在不再需要 viewModel 时获得回调,然后我们可以取消网络调用。如果应用程序未打开,我们可以继续进行网络调用,因为实时数据可以确保在正确的时间将数据从 ViewModel 传递到 View