Viewmodel connection to Repositorio

Asked

Viewed 44 times

-1

Hello, all right?

I have a scenario that is the following: on Android I need to connect my Viewmodel with Repository. I managed to do, though, I just don’t know if I did it the right way. Inside my Viewmodel I have a liveData, in my Viewmodel I make an asynchronous call with retrofit. I followed my implementation. Can I do this inside the Viewmode? Considering the high-cohesion and low-coupling?

private void carregarItems() {

    mListaMutableLiveDataServico = new MutableLiveData<List<ProdutoServico>>();
    mListaMutableLiveDataProduto = new MutableLiveData<List<ProdutoServico>>();

    MainAPI mMainAPI = ConfigServico.criarServico(MainAPI.class);
    Call<List<ProdutosServicos>> mCallModelMain = mMainAPI.obterEntidadesMain();

    mAlertDialog = new ProgressBarUtils(mContext).criarAlerta();
    mAlertDialog.show();

    mCallModelMain.enqueue(new Callback<List<ProdutosServicos>>() {
        @Override
        public void onResponse(Call<List<ProdutosServicos>> call, Response<List<ProdutosServicos>> response) {
            if(!response.isSuccessful())
                return;

            mListaMutableLiveDataProduto.setValue(response.body().get(0).getProdutos());
            mListaMutableLiveDataServico.setValue(response.body().get(1).getServicos());
        }

        @Override
        public void onFailure(Call<List<ProdutosServicos>> call, Throwable t) {
            Log.e("Error: ", t.getMessage());
        }
    });
}

1 answer

1

Hello, Vinicius!

Considering high cohesion and level of involvement the response is nay. In your code, you delegate tasks to ViewModel which relate to the Repository. How do you consider the use of a Repository, let him do the work himself and only then pass the data to ViewModel, leaving you in charge of UI management (Activity/Fragment) and your requests to this data. Let’s see in practice:

Messagesrepository.class

public class MessagesRepository {
    private MutableLiveData<ArrayList<Message>> mMessages;

    public MutableLiveData<ArrayList<Message>> getMessages(String uid) {
        if(mMessages == null) mMessages = new MutableLiveData();

        // Faça sua chamada a base de dados aqui e use
        // o método postValue() do MutableLiveData em resultados 
        // de chamadas assíncronas

        return mMessages;
    }
}

Messagesviewmodel.class

public class MessagesViewModel extends ViewModel {
    private MessagesRepository mRepository;

    public MessagesViewModel(MessagesRepository repository) {
        mRespository = repository;
    }

    public MutableLiveData<ArrayList<Message>> getMessages(String uid) {
        return mRepository.getMessages(uid);
    }
}

Realize that now the Repository is solely responsible for obtaining the data, regardless of where they are, as the ViewModel does not know where they come from. They may come from a local storage or an API, for example. This way, you can change your data source at any time without causing side effects on the other components. This is what is recommended by the documentation. However, access to the data can be done directly on ViewModel

Your ViewModel should not make any kind of decision or do anything other than submit the data to the UI, such as treat ProgressBar or Dialog. For that, use a Resource to be notified of the request status (loading, failure, empty, etc.).

EDIT 1:

1 - Create a Resource to "traffic" data and call states to ViewModel

Resource.java

public class Resource<T> {
    private State state;
    private T data;
    private String message;

    public void setData(T data) {
      this.data = data;
    }

    public T getData() {
       return data;
    }

    public void setState(State state) {
       this.state = state;
    }

    public State getState() {
      return state;
    }

    public void setMessage(String message) {
       this.message = message;
    }

    public String getMessage() {
      return message;
    }
}

2 - Create a enum to represent the states (these are basic states of any request)

Java state.

public enum State {
    SUCCESSFUL,
    FAILURE,
    EMPTY
}

3 - Update the Repository and the ViewModel to work with Resource

Messagesrepository.class

public class MessagesRepository {
    private MutableLiveData<Resource<ArrayList<Message>>> mMessages;

    public MutableLiveData<Resource<ArrayList<Message>>> getMessages(String uid) {
        if(mMessages == null) mMessages = new MutableLiveData();

        // Seta o estado inicial e manda isso p/ ViewModel/UI
        Resource<ArrayList<Message>> resource = new Resource<>();
                                     resource.setState(State.LOADING);
        mMessages.setValue(resource);

        // Faça sua chamada a base de dados aqui e use
        // o método postValue() do MutableLiveData em resultados 
        // de chamadas assíncronas. Não esqueça de setar os estados
        // de sucesso e falha


        return mMessages;
    }
}

Messagesviewmodel.class

public class MessagesViewModel extends ViewModel {
    private MessagesRepository mRepository;

    public MessagesViewModel(MessagesRepository repository) {
        mRespository = repository;
    }

    public MutableLiveData<Resource<ArrayList<Message>>> getMessages(String uid) {
        return mRepository.getMessages(uid);
    }
}

4 - Now in your UI just manage the states showing loading/progress/alert and other things

Messagesactivity.java

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messages);

        mMessagesModel.getMessages(/* uid */)
              .observe(this, resource -> {
              if(resource.getState() == State.LOADING) {
                  // Carregando
              }
              else if (resource.getState() == State.SUCCESSFUL) {
                  // Carregado com êxito
                  ArrayList<Message> messages = resource.getData();
              }
              else if (resource.getState() == State.FAILURE) {
                  // Falha
              }
              else {
                  // Vazio
              }
        });
    }

That’s the basics. Everything can improve, especially in development. Use this as a starting point. I hope it helps!

  • Very cool your answer, I have implemented the suggested pattern and it was much better and intelligible. Now, to get the status of the request, do you have an example of how I can use this Resource? That part for me is still a little abstract.

  • I updated my answer. I implemented an example of using Resource

Browser other questions tagged

You are not signed in. Login or sign up in order to post.