Android存储库模式:如何将额外的数据传递给Fragment / Activity

时间:2018-11-01 08:19:55

标签: android retrofit repository-pattern android-jetpack

我阅读了本指南:https://developer.android.com/jetpack/docs/guide enter image description here  并尝试在这种情况下使用存储库模式:

通过翻新库

app向服务器/get/user发出GET请求,服务器的响应可能是这样的(状态200):

 {
    "user": {"name" : "Jack", "id": "99"},
    "status": true
 }

或类似这样(状态200):

{ "status": false, "message": "Some error here"}

或例如500错误。

我的UserFragment应该显示对话框,具体取决于服务器响应:如果一切正常-正常消息,如果状态为false-来自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
}

我应该如何以存储库模式处理它?<​​/ p>

  1. 我的存储库对象是否应将User返回到ViewModel?如果是,我的ViewModel如何知道api响应的状态和消息字段?
  2. 或者我的存储库对象应该直接将ApiResponse返回给ViewModel,然后ViewModel从中获取状态,消息和用户,并将它们传递给Fragment?但是,如果我要将用户缓存到数据库怎么办?我们需要将所有ApiResponse存储到数据库还是需要仅存储用户?
  3. 还有其他...?

我更喜欢1,因为对我来说更清楚了,但是我的问题-如何处理从服务器返回的状态和消息字段,并需要在Fragment中显示数据。

4 个答案:

答案 0 :(得分:1)

这取决于您计划在Fragment上显示哪些信息。

如果网络出现问题,您是否会向用户显示错误消息?还是只显示“找不到用户”消息,您会感到高兴。

您打算向用户显示的数据应进入ViewModel

如果要直接显示来自Api的错误消息,请将其传递给ViewModel

如果仅打算显示用户,则将其传递给ViewModel。在这种情况下,错误消息只能被概括。

答案 1 :(得分:1)

这是我的操作方式:

存储库:

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; }

ViewModel:

public LiveData<User> user = Repository.getInstance().getUserData();

在这种情况下,您的viewModel不会每次都创建liveData,它将从存储库中获取liveData。此外,您将在您的仓库中加载数据,因此您不必经常触发调用。

如果您需要了解每个呼叫状态,请使用liveData和response obj livedata内的NetworkState枚举创建类似DataSource Holder对象之类的东西

这是我的RemoteDataSource:

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();
            }
        }
    }
}

答案 2 :(得分:1)

我使用存储库模式来保持简单的动作来检索所需的信息,没有什么真正复杂的:

https://github.com/ApploverSoftware/android-mvvm-architecture/blob/master/app/src/main/java/pl/applover/architecture/mvvm/data/example/repositories/ExampleCitiesRepository.kt

/**
 * 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() }!!

}

此外,我正在将“后端模型”映射到应用程序模型(我不喜欢创建一个模型,因为后端可以更改其模型,然后迫使我们也更改模型)。就是这样,我可以获取要使用的模型,可以使用Rx的dispose结束通话,也可以使用此获取错误代码或消息。

ViewModels与此配合良好,因为当不再需要viewModel时我们可以获取回调,然后我们可以取消网络调用。如果没有打开应用程序,我们可以继续进行网络呼叫,因为实时数据可以确保在正确的时间将数据从ViewModel传递到View

答案 3 :(得分:0)

使用翻新,
您可以在回调类中获得响应,
您必须创建一个扩展该类的新类,

library(dplyr)
df %>% mutate(A=hours-lag(hours), B=if_else(is.na(A) | A!=-23,0,1), date=181010+cumsum(B==1))
  #%>% select(-A,-B) #If you don't need them

  time.sub         hms hours   A B   date
1 23:59:53 23H 59M 53S    23  NA 0 181010
2 23:59:55 23H 59M 55S    23   0 0 181010
3 23:59:57 23H 59M 57S    23   0 0 181010
4 23:59:59 23H 59M 59S    23   0 0 181010
5    0:0:1          1S     0 -23 1 181011
6    0:0:3          3S     0   0 0 181011

别忘了覆盖onFailure。