Benfactor
Benfactor

Reputation: 599

How can I refresh viewModel livedata from another activity

I am developing android application and I want to refresh viewModel livedata from second activity. When I get back to first activity data is not refreshed.

FirstActivity:

 mViewModel = ViewModelProviders.of(this).get(MenuViewModel.class);

mViewModel.getMenus().observe(this, menuResponse -> {
            if (menuResponse != null) {
                resMenus.addAll(menuResponse.getMenus());
                progressBar.setVisibility(View.GONE);
                mAdapter.notifyDataSetChanged();
            }
        });

MenuViewModel:

public class MenuViewModel extends AndroidViewModel {
    private MutableLiveData<MenuResponse> restMenuData;
    private MenusRepository mRepository;

    public MainActivityViewModel(@NonNull Application application) {
        super(application);
        mRepository = MenusRepository.getInstance(application);
        restMenuData = mRepository.getMenus();
    }

    public LiveData<MenuResponse> getMenus() {
        return restMenuData;
    }
}

MenusRepository

 private MenusRepository(Context context) {
        apiRequest= RetrofitInstance.getInstance(context).getApiRequest();
    }

    public synchronized static MenusRepository getInstance(Context context) {
        if (projectRepository == null) {
            projectRepository = new MenusRepository(context);
        }
        return projectRepository;
    }

public MutableLiveData<MenuResponse> getMenus() {
        final MutableLiveData<MenuResponse> data = new MutableLiveData<>();
        apiRequest.getMenus().enqueue(new Callback<MenuResponse>() {
            @Override
            public void onResponse(@NonNull Call<MenuResponse> call, @NonNull Response<MenuResponse> response) {
                if (response.isSuccessful() && response.body() != null) {
                    data.setValue(response.body());
                }
            }

            @Override
            public void onFailure(@NonNull Call<MenuResponse> call, @NonNull Throwable t) {
                data.setValue(null);
            }
        });
        return data;
    }

SecondActivity:

MenuViewModel mViewModel = ViewModelProviders.of(Objects.requireNonNull(SecondActivity.this)).get(MenuViewModel.class);
        mViewModel.getMenus();
// This line not refresh menus

I except to refresh data from viewmodel, but it return old data. How can I refresh viewmodel data in best practices?

Upvotes: 4

Views: 5584

Answers (2)

Froyo
Froyo

Reputation: 18477

MenusRepository.getMenus() methods creates a new instance of LiveData for every call. This is not the correct way to go about it.

You should have only one instance of LiveData and different objects subscribe to it (activity, viewModel, etc).

What you could do is - create a singleton of MenusRepository (which I think you have already done). Create one instance of MutableLiveData only and use it to update the data.

class MenusRepository {
    private val liveData = MutableLiveData<MenuResponse>()

    fun getMenus() {
        // Your api call. Do not create a new instance of the livedata.
    }

    fun menus(): LiveData<MenuResponse> {
        return liveData
    }

    fun update(data: MenuResponse) {
        liveData.post(data)
    }

This code is in Kotlin, but it applies similarly to Java as well.

You can update method to post an update to liveData. When you update it, all the observers will receive the new data. Use MenusRepository.menus() to access LiveData in your ViewModel.


Update

Your MenuRepository class could be like this.

private final MutableLiveData<MenuResponse> liveData = new MutableData<>();
private MenusRepository(Context context) {
    apiRequest= RetrofitInstance.getInstance(context).getApiRequest();
}

public synchronized static MenusRepository getInstance(Context context) {
    if (projectRepository == null) {
        projectRepository = new MenusRepository(context);
    }
    return projectRepository;
}

public MutableLiveData<MenuResponse> loadMenus() {
    apiRequest.getMenus().enqueue(new Callback<MenuResponse>() {
        @Override
        public void onResponse(@NonNull Call<MenuResponse> call, @NonNull Response<MenuResponse> response) {
            if (response.isSuccessful() && response.body() != null) {
                liveData.setValue(response.body());
            }
        }

        @Override
        public void onFailure(@NonNull Call<MenuResponse> call, @NonNull Throwable t) {
            liveData.setValue(null);
        }
    });
}

public LiveData<MenuResponse> getMenus() {
    return liveData;
}

public void updateData(response: MenuResponse) {
    liveData.postValue(response);
}
  • When you want to update the data manually (from another activity), use menuRepository.update() method. This will post the data to your LiveData which will update all its observers, ie. the ViewModel.
  • Call menuRepository.loadMenu() when you want to get the data using API.
  • Use menuRepository.getMenus() to get the LiveData and attach your observers.

Since MenuRepository is a singleton, there's only one instance of LiveData. When you will post an update to this instance of LiveData, all the observers will receive the new data.

Upvotes: 3

Antonio
Antonio

Reputation: 1274

public class MenuViewModel extends AndroidViewModel {
private MutableLiveData<MenuResponse> restMenuData;
private MenusRepository mRepository;

public MainActivityViewModel(@NonNull Application application) {
    super(application);
    mRepository = MenusRepository.getInstance(application);
    restMenuData = mRepository.getMenus();
}

public LiveData<MenuResponse> getMenus() {
    restMenuData = new MutableLiveData<>();
    return restMenuData;
}
}

Change the View model code as above. So that the live data is always cleared before returning to activity.

Upvotes: 0

Related Questions