Skip to content

Commit

Permalink
Setup persistence for NowPlayingFragment.java
Browse files Browse the repository at this point in the history
  • Loading branch information
ShashankSinha98 committed Apr 4, 2022
1 parent d241754 commit ec67f27
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 24 deletions.
18 changes: 15 additions & 3 deletions app/src/main/java/com/shashank/moviedb/data/local/MovieDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import androidx.room.Query;

import com.shashank.moviedb.model.MovieResult;
import com.shashank.moviedb.model.NowPlayingMovieIdsEntity;
import com.shashank.moviedb.model.TrendingMovieIdsEntity;

import java.util.List;

Expand All @@ -23,12 +25,22 @@ public interface MovieDao {
void insertMovieResults(MovieResult... movieResults);

@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertMovieResult(MovieResult movieResult);
void insertTrendingMovieIds(TrendingMovieIdsEntity... trendingMovieIds);

@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertNowPlayingMovieIds(NowPlayingMovieIdsEntity... trendingMovieIds);


@Query("SELECT * FROM movies")
Flowable<List<MovieResult>> getMovieResults();

@Query("SELECT COUNT(*) FROM movies")
Flowable<Integer> getMovieCount();
@Query("SELECT * FROM trending_movie_ids")
Flowable<List<TrendingMovieIdsEntity>> getTrendingMovieIds();

@Query("SELECT * FROM nowplaying_movie_ids")
Flowable<List<NowPlayingMovieIdsEntity>> getNowPlayingMovieIds();

@Query("SELECT * FROM movies WHERE id IN (:movieIds)")
Flowable<List<MovieResult>> getMovieResultsForMovieIds(List<Long> movieIds);

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
import androidx.room.Database;
import androidx.room.RoomDatabase;
import com.shashank.moviedb.model.MovieResult;
import com.shashank.moviedb.model.NowPlayingMovieIdsEntity;
import com.shashank.moviedb.model.TrendingMovieIdsEntity;

@Database(entities = {
MovieResult.class
MovieResult.class,
TrendingMovieIdsEntity.class,
NowPlayingMovieIdsEntity.class
}, version = 1, exportSchema = false)
public abstract class MovieDatabase extends RoomDatabase {
public abstract MovieDao getMovieDao();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.shashank.moviedb.data.remote;

import static com.shashank.moviedb.util.Constants.*;
import static com.shashank.moviedb.util.Constants.TRENDING_TIME_WINDOW;

import android.util.Log;
Expand All @@ -9,13 +10,14 @@
import com.shashank.moviedb.data.ResourceCallback;
import com.shashank.moviedb.data.Resource;
import com.shashank.moviedb.data.local.MovieDao;
import com.shashank.moviedb.data.local.MovieDatabase;
import com.shashank.moviedb.model.MovieDetail;
import com.shashank.moviedb.model.MovieResponse;
import com.shashank.moviedb.model.MovieResult;
import com.shashank.moviedb.util.Constants;
import com.shashank.moviedb.model.NowPlayingMovieIdsEntity;
import com.shashank.moviedb.model.TrendingMovieIdsEntity;
import com.shashank.moviedb.util.Constants.QueryParams;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

Expand All @@ -24,7 +26,6 @@
import io.reactivex.Completable;
import io.reactivex.CompletableObserver;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;
Expand All @@ -50,8 +51,8 @@ public void fetchNowPlayingMovies(ResourceCallback resourceCallback) {

movieApi.fetchNowPlayingMovie(QueryParams.PARAMS_NOW_PLAYING_MOVIE_API)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.delay(Constants.DUMMY_NETWORK_DELAY, TimeUnit.MILLISECONDS)
//.observeOn(AndroidSchedulers.mainThread())
.delay(DUMMY_NETWORK_DELAY, TimeUnit.MILLISECONDS)
.subscribe(new Observer<MovieResponse>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Expand All @@ -61,13 +62,17 @@ public void onSubscribe(@NonNull Disposable d) {
@Override
public void onNext(@NonNull MovieResponse movieResponse) {
Log.d(TAG,"fetchNowPlayingMovies - onNext: movieResponse: "+movieResponse);
resourceCallback.onResponse(Resource.success(movieResponse));
try {
processMovieResponse(movieResponse, resourceCallback, STATUS_NOW_PLAYING);
} catch (Exception e) {
resourceCallback.onResponse(Resource.error(e.getMessage(), null));
}
}

@Override
public void onError(@NonNull Throwable e) {
Log.d(TAG, "fetchNowPlayingMovies - onError: e: "+e.getMessage());
resourceCallback.onResponse(Resource.error(e.getMessage(), null));
checkMovieDataInDatabase(resourceCallback, STATUS_NOW_PLAYING);
}

@Override
Expand All @@ -85,7 +90,7 @@ public void fetchTrendingMovies(ResourceCallback resourceCallback) {
movieApi.fetchTrendingMovie(TRENDING_TIME_WINDOW, QueryParams.PARAMS_TRENDING_MOVIE_API)
.subscribeOn(Schedulers.io())
//.observeOn(AndroidSchedulers.mainThread())
.delay(Constants.DUMMY_NETWORK_DELAY, TimeUnit.MILLISECONDS)
.delay(DUMMY_NETWORK_DELAY, TimeUnit.MILLISECONDS)
.subscribe(new Observer<MovieResponse>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Expand All @@ -95,15 +100,18 @@ public void onSubscribe(@NonNull Disposable d) {
@Override
public void onNext(@NonNull MovieResponse movieResponse) {
Log.d(TAG,"fetchTrendingMovies - onNext: movieResponse: "+movieResponse);
//resourceCallback.onResponse(Resource.success(movieResponse));
processMovieResponse(movieResponse, resourceCallback);
try {
processMovieResponse(movieResponse, resourceCallback, STATUS_TRENDING);
} catch (Exception e) {
resourceCallback.onResponse(Resource.error(e.getMessage(), null));
}
}

@Override
public void onError(@NonNull Throwable e) {
Log.d(TAG, "xlr8: fetchTrendingMovies - onError: e: "+e.getMessage());
//resourceCallback.onResponse(Resource.error(e.getMessage(), null));
checkDataInDatabase(resourceCallback);
checkMovieDataInDatabase(resourceCallback, STATUS_TRENDING);
}

@Override
Expand All @@ -118,7 +126,7 @@ public void onComplete() {
public void fetchMovieDetail(Long movieId, ResourceCallback resourceCallback) {

if(movieId==null || movieId<=0L) {
resourceCallback.onResponse(Resource.error(Constants.INVALID_MOVIE_ID_ERROR_MSG,null));
resourceCallback.onResponse(Resource.error(INVALID_MOVIE_ID_ERROR_MSG,null));
return;
}

Expand Down Expand Up @@ -151,9 +159,10 @@ public void onComplete() {
}


/********************************************** PRIVATE HELPER FUNCTIONS *****************************************************************************/

// Save remote data in room db, read data from db and then pass it to callback
private void processMovieResponse(MovieResponse movieResponse, ResourceCallback callback) {
private void processMovieResponse(MovieResponse movieResponse, ResourceCallback callback, int movieStatus) throws Exception {
Log.d(TAG, "xlr8: processMovieResponse called: movieResponse: "+movieResponse);

if(movieResponse==null || movieResponse.getResults()==null || movieResponse.getResults().isEmpty()) {
Expand All @@ -163,13 +172,18 @@ private void processMovieResponse(MovieResponse movieResponse, ResourceCallback

List<MovieResult> movies = movieResponse.getResults();

// Insert movies data in database
// step 1- Insert movies data in database
Completable.fromAction(new Action() {
@Override
public void run() throws Exception {

// Step 1.1- Insert movie ids into respective Entity
insertMovieIdsIntoRespectiveEntity(movies, movieStatus);

// Step 1.2- Insert MovieResult in main movie table
movieDao.insertMovieResults(movies.toArray(new MovieResult[movies.size()]));
}
}).subscribeOn(Schedulers.io())
}).subscribeOn(Schedulers.computation())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Expand All @@ -180,8 +194,9 @@ public void onSubscribe(@NonNull Disposable d) {
public void onComplete() {
Log.d(TAG, "xlr8: processMovieResponse: onComplete");
// Movies inserted in DB Successfully
// Fetch movies data from DB and pass it to callback
checkDataInDatabase(callback);

// Step 2- Fetch movies data from DB and pass it to UI
checkMovieDataInDatabase(callback, movieStatus);
}

@Override
Expand All @@ -192,11 +207,74 @@ public void onError(@NonNull Throwable e) {
});
}

private void insertMovieIdsIntoRespectiveEntity(List<MovieResult> movies, int movieStatus) {
if(movieStatus== STATUS_NOW_PLAYING) {
List<NowPlayingMovieIdsEntity> nowPlayingMovieIds = new ArrayList<>();
for(MovieResult movie: movies) {
nowPlayingMovieIds.add(new NowPlayingMovieIdsEntity(movie.getId()));
}
movieDao.insertNowPlayingMovieIds(nowPlayingMovieIds.toArray(new NowPlayingMovieIdsEntity[nowPlayingMovieIds.size()]));

private void checkDataInDatabase(ResourceCallback callback) {
} else if(movieStatus== STATUS_TRENDING) {
List<TrendingMovieIdsEntity> trendingMovieIds = new ArrayList<>();
for(MovieResult movie: movies) {
trendingMovieIds.add(new TrendingMovieIdsEntity(movie.getId()));
}
movieDao.insertTrendingMovieIds(trendingMovieIds.toArray(new TrendingMovieIdsEntity[trendingMovieIds.size()]));
}
}

// Check data in DB, if present - pass via callback
private void checkMovieDataInDatabase(ResourceCallback callback, int movieStatus) {
Log.d(TAG, "xlr8 : checkDataInDatabase called");

// Step 2.1 - Get list of movie ids from respective movie status table
if(movieStatus==STATUS_TRENDING) {
movieDao.getTrendingMovieIds().subscribeOn(Schedulers.io())
.subscribe(new Consumer<List<TrendingMovieIdsEntity>>() {
@Override
public void accept(List<TrendingMovieIdsEntity> trendingMovieIdsEntities) throws Exception {
if(trendingMovieIdsEntities!=null && !trendingMovieIdsEntities.isEmpty()) {
List<Long> trendingMovieIds = new ArrayList<>();
for(TrendingMovieIdsEntity trendingMovieIdsEntity: trendingMovieIdsEntities) {
trendingMovieIds.add(trendingMovieIdsEntity.getMovieId());
}

// Step 2.2- fetch movie of these ids only
checkMovieDataInDatabaseForIds(callback, trendingMovieIds);
} else {
callback.onResponse(Resource.error("Error/Empty response while querying DB", null));
}
}
});

}
// Step 2.1 - Get list of movie ids from respective movie status table
else if(movieStatus==STATUS_NOW_PLAYING) {
movieDao.getNowPlayingMovieIds().subscribeOn(Schedulers.io())
.subscribe(new Consumer<List<NowPlayingMovieIdsEntity>>() {
@Override
public void accept(List<NowPlayingMovieIdsEntity> nowPlayingMovieIdsEntities) throws Exception {
if(nowPlayingMovieIdsEntities!=null && !nowPlayingMovieIdsEntities.isEmpty()) {
List<Long> nowPlayingMovieIds = new ArrayList<>();
for(NowPlayingMovieIdsEntity nowPlayingMovieIdsEntity: nowPlayingMovieIdsEntities) {
nowPlayingMovieIds.add(nowPlayingMovieIdsEntity.getMovieId());
}

// Step 2.2- fetch movie of these ids only
checkMovieDataInDatabaseForIds(callback, nowPlayingMovieIds);
} else {
callback.onResponse(Resource.error("Error/Empty response while querying DB", null));
}
}
});
}

}

private void checkMovieDataInDatabaseForIds(ResourceCallback callback, List<Long> movieIds) {
// Fetch movies data from DB
movieDao.getMovieResults().subscribeOn(Schedulers.io())
movieDao.getMovieResultsForMovieIds(movieIds).subscribeOn(Schedulers.io())
.subscribe(new Consumer<List<MovieResult>>() {
@Override
public void accept(List<MovieResult> movieResults) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class MovieResult {
@ColumnInfo(name = "vote_average")
@Nullable @SerializedName("vote_average") private Double voteAverage;


public MovieResult() { }

public MovieResult(@NonNull Long id, @NonNull String originalTitle, @NonNull String title, @Nullable String posterPath,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.shashank.moviedb.model;

import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;

@Entity(tableName = "nowplaying_movie_ids")
public class NowPlayingMovieIdsEntity {

@PrimaryKey(autoGenerate = false)
@ColumnInfo(name = "movie_id")
private Long movieId;

public NowPlayingMovieIdsEntity(Long movieId) {
this.movieId = movieId;
}

public Long getMovieId() {
return movieId;
}

public void setMovieId(Long movieId) {
this.movieId = movieId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.shashank.moviedb.model;

import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;

@Entity(tableName = "trending_movie_ids")
public class TrendingMovieIdsEntity {

@PrimaryKey(autoGenerate = false)
@ColumnInfo(name = "movie_id")
private Long movieId;

public TrendingMovieIdsEntity(Long movieId) {
this.movieId = movieId;
}

public Long getMovieId() {
return movieId;
}

public void setMovieId(Long movieId) {
this.movieId = movieId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public void onChanged(Resource<List<MovieResult>> listResource) {
swipeRefreshLayout.setRefreshing(false);
movieRecyclerView.setVisibility(View.VISIBLE);
noInternetView.update(Status.SUCCESS, null);
List<MovieResult> movies = ((MovieResponse)listResource.getData()).getResults();
List<MovieResult> movies = listResource.getData();
if(movies!=null && !movies.isEmpty()){
movieRecyclerAdapter.setMovies(movies);
}
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/com/shashank/moviedb/util/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ public abstract class Constants {
public static final Long DUMMY_NETWORK_DELAY = 1500L;


public static final int STATUS_TRENDING = 0;
public static final int STATUS_NOW_PLAYING = 1;





Expand Down

0 comments on commit ec67f27

Please sign in to comment.