Шаблон репозитория Android: как передавать дополнительные данные в Fragment / Activity - PullRequest
0 голосов
/ 01 ноября 2018

Я прочитал это руководство: https://developer.android.com/jetpack/docs/guide enter image description here и попробуйте использовать шаблон репозитория в этом случае:

приложение через Retrofit lib делает запрос GET к серверу /get/user, и ответ от сервера может быть таким (со статусом 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
}

Как мне с этим справиться в репозитории?

  1. Должен ли мой объект репозитория возвращать пользователя в ViewModel? Если да - как моя ViewModel узнала о статусе и полях сообщения ответа API?
  2. Или мой объект хранилища должен возвращать напрямую ApiResponse ViewModel, и ViewModel получает от него статус, сообщение и пользователя и передает их Fragment? Но что, если я хочу кешировать пользователя в базу данных? Нужно ли хранить все ApiResponse в базе данных или нам нужен только пользователь Store?
  3. Или что-то еще ...?

Я предпочитаю 1, потому что для меня это более понятно, но моя проблема - как обращаться с полями статуса и сообщения, возвращенными с сервера и необходимыми для отображения данных во фрагменте.

Ответы [ 4 ]

0 голосов
/ 06 ноября 2018

Я использую шаблон репозитория, чтобы просто выполнять простые действия для получения необходимой информации, ничего сложного:

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 в нужное время

0 голосов
/ 01 ноября 2018

Используя Retrofit,
Вы можете получить ответ в Callback Class,
Вы должны создать новый класс, расширяющий,

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

не забудьте перезаписать при сбое.

0 голосов
/ 01 ноября 2018

Вот как я это делаю:

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

В этом случае ваш viewModel не будет создавать liveData каждый раз, он будет получать liveData из репозитория. Более того, вы загрузите данные в репо, так что вам не придется часто звонить.

Если вам нужно знать о каждом статусе вызова, создайте что-то вроде объекта-держателя DataSource с вашим перечислением NetworkState внутри liveData и ответом obj aliveata

Вот мой 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();
            }
        }
    }
}
0 голосов
/ 01 ноября 2018

Немного зависит от того, какую информацию вы планируете отображать на Fragment.

Будете ли вы показывать пользователю сообщения об ошибках, если есть проблема с сетью? Или вы будете рады показать сообщение «пользователь не найден».

Данные, которые вы планируете показать пользователю, должны попасть в ViewModel.

Если вы намереваетесь показать сообщение об ошибке непосредственно от Api, передайте его ViewModel.

Если вы намереваетесь показать только пользователя, передайте это ViewModel. В этом случае сообщения об ошибках могут быть только обобщенными.

...