1

I'm using the Retrofit client to perform HTTP requests in a simple Android project. When I send a CREATE request, the item is successfully created in the remote SQLite database, but the ViewModel still contains the old list. When I restart my application, and fetch again all items from the server, the item appears.

I'm following the Android - Guide to app archcitecture and I use LiveData objects both in my Repository and ViewModel.

My Fragment adds an Observer to the LiveData object in ViewModel:

mViewModel.getAllItems().observe(getActivity(), new Observer<List<Item>>() {
            @Override
            public void onChanged(@Nullable final List<Item> items) {
                // Update the cached copy of the words in the adapter.
                mAdapter.setItems(items);
                mAdapter.notifyDataSetChanged();
            }
        });

The onChange() function is fired after I send a CREATE request, but the list of items has not changed.

Retrofit version:

// Retrofit
implementation('com.squareup.retrofit2:retrofit:2.5.0') {
    exclude module: 'okhttp'
}
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
implementation 'com.squareup.okhttp3:okhttp:3.6.0'
implementation "com.squareup.okhttp3:logging-interceptor:3.6.0"

EDIT

Relevant code:

ItemViewModel.java

public class ItemViewModel extends AndroidViewModel {

    private ItemRepository mItemRepository;
    private LiveData<List<Item>> items;

    public ItemViewModel(Application application) {
        super(application);
        this.mItemRepository = new ItemRepository();
    }

    public LiveData<List<Item>> getAllItems() {
        if (this.items == null) {
            this.items = mItemRepository.getAllItems();
        }
        return this.items;
    }

    public void createItem(Item item) {
        this.mItemRepository.createItem(item);
    }

}

ItemRepository.java

public class ItemRepository {

    private WebService mWebservice;
    private MutableLiveData<List<Item>> mAllItems = new MutableLiveData<>();

    public ItemRepository() {
        this.mWebservice = WebClient.getClient().create(WebService.class);
    }

    public LiveData<List<Item>> getAllItems() {
        final MutableLiveData<List<Item>> data = new MutableLiveData<>();
        this.mWebservice.getAllItems().enqueue(new Callback<GetAllItemsResponse>() {
            @Override
            public void onResponse(Call<GetAllItemsResponse> call, Response<GetAllItemsResponse> response) {
                data.setValue(response.body().items);
            }
            @Override
            public void onFailure(Call<GetAllItemsResponse> call, Throwable t) {
                System.out.println(t);
            }
        });
        return data;
    }

    public void insertItem(Item item) {
        mWebservice.createItem(item);
    }

}
mjkdr
  • 66
  • 1
  • 5

2 Answers2

0

You just need to fetch the data when you actually say "you want to fetch the data". So you could make a LiveData in which you can fetch the new data.

public class RefreshLiveData<T> extends MutableLiveData<T> {
    public interface RefreshAction<T> {
        private interface Callback<T> {
             void onDataLoaded(T t);
        }

        void loadData(Callback<T> callback);
    }

    private final RefreshAction<T> refreshAction;
    private final Callback<T> callback = new RefreshAction.Callback<T>() {
          @Override
          public void onDataLoaded(T t) {
               postValue(t);
          }
    };

    public RefreshLiveData(RefreshAction<T> refreshAction) {
        this.refreshAction = refreshAction;
    }

    public final void refresh() {
        refreshAction.loadData(callback);
    }
}

Then you can do

public class YourViewModel extends ViewModel {
    private RefreshLiveData<List<Item>> items;

    private final ItemRepository itemRepository;

    public YourViewModel(ItemRepository itemRepository) {
         this.itemRepository = itemRepository;
         items = itemRepository.getAllItems();
    }

    public void refreshData() {
        items.refresh();
    }

    public LiveData<List<Item>> getItems() {
        return items;
    }
}

And then repository can do:

public RefreshLiveData<List<Item>> getAllItems() {
    final RefreshLiveData<List<Item>> liveData = new RefreshLiveData<>((callback) -> {
         mWebservice.getAllItems().enqueue(new Callback<List<Item>>() {
            @Override
            public void onResponse(Call<List<Item>> call, Response<List<Item>> response) {
                callback.onDataLoaded(response.body());
            }

            @Override
            public void onFailure(Call<List<Item>> call, Throwable t) {

            }
         });
    });

    return liveData;
}
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
-1
public class ItemViewModel extends AndroidViewModel {

    private ItemRepository mItemRepository;
    private LiveData<List<Item>> items;

    public ItemViewModel(Application application) {
        super(application);
        this.mItemRepository = new ItemRepository();
    }

    public LiveData<List<Item>> getAllItems() {
//      if (this.items == null) {
            this.items = mItemRepository.getAllItems();
//      }
        return this.items;
    }

    public void createItem(Item item) {
        this.mItemRepository.createItem(item);
    }

}

Try removing this if condition

mjkdr
  • 66
  • 1
  • 5
Kamal Kakkar
  • 314
  • 1
  • 4
  • 13
  • Thanks. Unfortunately, this does not fix my problem. I think that by reinstantiating the LiveData object each time you fetch items, the Observer that is instantiated once will observe old objects.. – mjkdr Jan 12 '19 at 14:52