Search code examples
androidandroid-livedataandroid-architecture-componentsandroid-mvvmandroid-paging

Is it a good practice to observeForever in Repository class? db+network paged list


Im building an app following architecture guidelines.Implemented room db caching + network.Need to get latest page number from separate entity.

My model:

@Entity(tableName = "top_rated_movie_page")
public class Top_Rated_Movies_Page {

@PrimaryKey(autoGenerate = true)
private int db_id;
private Integer page;
private Integer total_results;
private Integer total_pages;
@Ignore
private List<Result> results;
...

Result class contains data which i display in my paged list which observes changes from db.

Using PagedList.BoundaryCallback i need to fetch new data from network and insert it into db. But i need to get page number somehow. My dao:

@Insert
void insertAll(Top_Rated_Movies_Page page,List<Result> top_rated_results);

@Query("SELECT * FROM Result")
DataSource.Factory<Integer, Result> getAllResults();

@Query("SELECT * FROM top_rated_movie_page WHERE page= (SELECT MAX(page) FROM top_rated_movie_page)")
LiveData<Top_Rated_Movies_Page> getMoviePage();

I was thinking to observe Top_Rated_Movies_Page from db in my repository class with observeForever() to get that page number. Is that the best way to approach this?


Solution

  • Since the only time you'll read the next page key or update the backing DB is through BoundaryCallback, you can just read / write your next page key directly.

    So in your onItemAtEndLoad() implementation you want something like:

    String nextMoviePage = db.runInTransaction(() -> {
        movieDao.nextRemoteKey().key;
    });
    
    // Make sure not to run on main thread
    MovieNetworkResponse response = networkApi.fetchNextMoviePage(remoteKey);
    
    db.runInTransaction(() -> {
        movieDao.clearAll(); // Remove previous key
        movieDao.insertKey(RemoteKey(response.nextPageKey)); // Insert new key
        movieDao.insertAll(response.movies); // Update DataSource + invalidate()
    });
    

    Your DAO:

    @Insert
    void insertAll(List<Result> top_rated_results);
    
    @Query("SELECT * FROM Result")
    DataSource.Factory<Integer, Result> getAllResults();
    
    @Query("SELECT * FROM result_key LIMIT 1")
    String nextRemoteKey();
    
    @Insert
    void insertKey(RemoteKey remoteKey);
    

    And don't forget to clear out both the items and remoteKey whenever you expect to refresh the data!

    In the case where you want to keep track of different keys for query, you can simply add that column to your RemoteKey entity.

    FYI: Paging2 has been superseded by Paging3 (though just launched alpha01), here is the similar Paging3 sample which solves exactly your use-case: https://github.com/android/architecture-components-samples/blob/master/PagingWithNetworkSample/app/src/main/java/com/android/example/paging/pagingwithnetwork/reddit/repository/inDb/PageKeyedRemoteMediator.kt