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
}

我应该如何在存储库模式中处理它?

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

我更喜欢 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();
            }
        }
    }
}

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

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

}

此外,我正在将 "Backend models" 映射到应用程序模型(我不喜欢创建一个模型,因为后端可以更改他们的模型,然后它会迫使我们也更改我们的模型)。就是这样,我可以获得我想要处理的模型,可以使用 Rx 的处置结束调用或使用它获取错误代码或消息。

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