简体   繁体   English

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

[英]Android repository pattern: how pass extra data to Fragment/Activity

I read this guide: https://developer.android.com/jetpack/docs/guide 我阅读了本指南: https//developer.android.com/jetpack/docs/guide 在此输入图像描述 and try to use repository pattern in this case: 并尝试在这种情况下使用存储库模式:

app via Retrofit lib make GET request to server /get/user and response from server may be like this (with status 200): 应用程序通过Retrofit lib向服务器/get/user发出GET请求,服务器响应可能是这样的(状态为200):

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

or like this (with status 200): 或者像这样(状态200):

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

or, 500 error, for example. 或者,例如500错误。

My UserFragment should show dialog, dependent on server response: if all is ok - ok message, if status false - error message from api response, if 500 - other error message. 我的UserFragment应该显示对话框,取决于服务器响应:如果一切正常 - 好消息,如果状态为false - 来自api响应的错误消息,如果500 - 其他错误消息。

My POJO model looks like this: 我的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
}

How I should deal with it in repository pattern? 我应该如何在存储库模式中处理它?

  1. Does my repository object should return User to ViewModel? 我的存储库对象应该将User返回给ViewModel吗? If yes - how my ViewModel know about status and message fields of api response? 如果是 - 我的ViewModel如何知道api响应的状态和消息字段?
  2. Or my repository object should return Directly ApiResponse to ViewModel, and ViewModel got status, message and user from it and pass them to Fragment? 或者我的存储库对象应该将Directly ApiResponse返回给ViewModel,ViewModel从中获取状态,消息和用户并将它们传递给Fragment? But what if I want cache user to database? 但是,如果我想要缓存用户数据库怎么办? Does we need store all ApiResponse to database or we need Store only User? 我们是否需要将所有ApiResponse存储到数据库中,或者我们需要仅存储用户?
  3. Or something else...? 或者是其他东西...?

I prefer 1, because It's more clear for me, but my problem - how deal with status and message fields, returned from server and needed to display data in Fragment. 我更喜欢1,因为它对我来说更清楚,但我的问题 - 如何处理状态和消息字段,从服务器返回并需要在Fragment中显示数据。

It depends a little bit, on what information you plan to display on the Fragment . 这取决于您计划在Fragment上显示的信息。

Will you show error messages to the user if there is a problem with the network? 如果网络出现问题,您是否会向用户显示错误消息? Or will you be happy just showing a "user not found" message. 或者您会很高兴只显示“未找到用户”消息。

Data that you plan to show the user should make its way into the ViewModel . 您计划向用户显示的数据应该进入ViewModel

If you intend to show the error message from the Api directly, pass that to the ViewModel . 如果您打算直接从Api显示错误消息,请将其传递给ViewModel

If you intend to show the user only, then pass that to the ViewModel . 如果您打算仅显示用户,请将其传递给ViewModel In this case, the error messages can only be generalized. 在这种情况下,错误消息只能是一般化的。

Here is how I do this: 我是这样做的:

Repository: 库:

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

In this case you viewModel won't create liveData each time, it will take liveData from Repository. 在这种情况下,viewModel每次都不会创建liveData,它将从Repository中获取liveData。 Moreover, u will have loaded data inside your repo, so you will not have to trigger calls that often. 此外,您将在repo中加载数据,因此您不必经常触发调用。

If you need to have knowledge of each call status, create something like DataSource holder object with your NetworkState enum inside liveData and response obj livedata 如果您需要了解每个调用状态,请在liveData和response obj livedata中使用NetworkState枚举创建类似DataSource holder对象的内容

Here is my RemoteDataSource: 这是我的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();
            }
        }
    }
}

I use repository pattern to just keep simple actions to retrieve the needed infos, nothing really complex: 我使用存储库模式来保持简单的操作来检索所需的信息,没有什么真正复杂的:

https://github.com/ApploverSoftware/android-mvvm-architecture/blob/master/app/src/main/java/pl/applover/architecture/mvvm/data/example/repositories/ExampleCitiesRepository.kt 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() }!!

}

Additionally I am mapping "Backend models" to app models (I don't like creating one model as backend can change their model and then it forces us to change our model too). 另外我将“后端模型”映射到应用模型(我不喜欢创建一个模型,因为后端可以改变他们的模型,然后它也迫使我们改变我们的模型)。 That's all, I can get model that I want to work on, posibility to end the call using Rx's dispose or get error code or message using this. 总而言之,我可以获得我想要处理的模型,使用Rx的dispose结束调用的可能性,或使用此获取错误代码或消息。

ViewModels work nicely with this as we can get callback when viewModel is not needed anymore and then we can cancel network calls. ViewModels与此工作很好,因为我们可以在不再需要viewModel时获得回调,然后我们可以取消网络调用。 We can continue making network calls if application isn't opened as live data secures to deliver the data from ViewModel to View in right time 如果未打开应用程序,我们可以继续进行网络调用,因为实时数据可确保在适当的时间将数据从ViewModel传递到View

Using Retrofit, 使用Retrofit,
you can get response in Callback Class, 你可以在Callback Class中得到响应,
you must create a new 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
        }
    }
}

don't forget to overwrite onFailure. 别忘了覆盖onFailure。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM