Retain comments after orientation changes in ViewPostDetailActivity.

This commit is contained in:
Alex Ning 2019-07-08 23:54:54 +08:00
parent 69b08a6d56
commit 4338dbd277
6 changed files with 33 additions and 333 deletions

View File

@ -37,8 +37,9 @@ public class SubredditViewModel extends AndroidViewModel {
this.subredditName = subredditName; this.subredditName = subredditName;
} }
@NonNull
@Override @Override
public <T extends ViewModel> T create(Class<T> modelClass) { public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection unchecked //noinspection unchecked
return (T) new SubredditViewModel(mApplication, subredditName); return (T) new SubredditViewModel(mApplication, subredditName);
} }

View File

@ -1,189 +0,0 @@
package ml.docilealligator.infinityforreddit;
import androidx.annotation.NonNull;
import androidx.lifecycle.MutableLiveData;
import androidx.paging.PageKeyedDataSource;
import java.util.Locale;
import retrofit2.Retrofit;
public class CommentDataSource extends PageKeyedDataSource<String, Post> {
interface OnCommentFetchedCallback {
void hasComment();
void noComment();
}
private Retrofit retrofit;
private Locale locale;
private String subredditNamePrefixed;
private String article;
private String comment;
private boolean isPost;
private OnCommentFetchedCallback onCommentFetchedCallback;
private MutableLiveData<NetworkState> paginationNetworkStateLiveData;
private MutableLiveData<NetworkState> initialLoadStateLiveData;
private LoadInitialParams<String> initialParams;
private LoadInitialCallback<String, Post> initialCallback;
private LoadParams<String> params;
private LoadCallback<String, Post> callback;
private String mParentId;
CommentDataSource(Retrofit retrofit, Locale locale, String subredditNamePrefixed, String article,
String comment, boolean isPost, OnCommentFetchedCallback onCommentFetchedCallback) {
this.retrofit = retrofit;
this.locale = locale;
this.subredditNamePrefixed = subredditNamePrefixed;
this.article = article;
this.comment = comment;
this.isPost = isPost;
paginationNetworkStateLiveData = new MutableLiveData();
initialLoadStateLiveData = new MutableLiveData();
this.onCommentFetchedCallback = onCommentFetchedCallback;
}
MutableLiveData getPaginationNetworkStateLiveData() {
return paginationNetworkStateLiveData;
}
MutableLiveData getInitialLoadStateLiveData() {
return initialLoadStateLiveData;
}
@Override
public void loadInitial(@NonNull LoadInitialParams<String> params, @NonNull LoadInitialCallback<String, Post> callback) {
initialParams = params;
initialCallback = callback;
initialLoadStateLiveData.postValue(NetworkState.LOADING);
RedditAPI api = retrofit.create(RedditAPI.class);
//Call<String> comments = api.getComments(subredditNamePrefixed, article, comment);
/*comments.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
if(response.isSuccessful()) {
ParseComment.parseComment(response.body(), new ArrayList<>(), locale, isPost,
0, new ParseComment.ParseCommentListener() {
@Override
public void onParseCommentSuccess(List<?> commentData, String parentId,
String commaSeparatedChildren) {
if(commentData.size() > 0) {
onCommentFetchedCallback.hasComment();
mParentId = parentId;
} else {
onCommentFetchedCallback.noComment();
}
callback.onResult((List<Post>) commentData, null, commaSeparatedChildren);
initialLoadStateLiveData.postValue(NetworkState.LOADED);
}
@Override
public void onParseCommentFailed() {
initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing comment"));
}
});
} else {
Log.i("comment call failed", response.message());
initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing comment"));
}
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error fetching comment"));
}
});*/
}
@Override
public void loadBefore(@NonNull LoadParams<String> params, @NonNull LoadCallback<String, Post> callback) {
}
@Override
public void loadAfter(@NonNull LoadParams<String> params, @NonNull LoadCallback<String, Post> callback) {
this.params = params;
this.callback = callback;
if(params.key.equals("null") || params.key.equals("")) {
return;
}
paginationNetworkStateLiveData.postValue(NetworkState.LOADING);
RedditAPI api = retrofit.create(RedditAPI.class);
//Call<String> moreChildrenBasicInfo = api.getMoreChildren(mParentId, params.key);
/*moreChildrenBasicInfo.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
if(response.isSuccessful()) {
ParseComment.parseMoreCommentBasicInfo(response.body(), new ParseComment.ParseMoreCommentBasicInfoListener() {
@Override
public void onParseMoreCommentBasicInfoSuccess(String commaSeparatedChildrenId) {
Call<String> moreComments = api.getInfo(subredditNamePrefixed, commaSeparatedChildrenId);
moreComments.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
if(response.isSuccessful()) {
ParseComment.parseMoreComment(response.body(), new ArrayList<>(), locale,
0, new ParseComment.ParseCommentListener() {
@Override
public void onParseCommentSuccess(List<?> commentData, String parentId,
String commaSeparatedChildren) {
callback.onResult((List<Post>) commentData, null);
paginationNetworkStateLiveData.postValue(NetworkState.LOADED);
}
@Override
public void onParseCommentFailed() {
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data"));
}
});
} else {
Log.i("comment call failed", response.message());
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, response.message()));
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
String errorMessage = t == null ? "unknown error" : t.getMessage();
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage));
}
});
}
@Override
public void onParseMoreCommentBasicInfoFailed() {
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Parse more comments basic info failed"));
}
});
} else {
Log.i("comment call failed", response.message());
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, response.message()));
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
String errorMessage = t == null ? "unknown error" : t.getMessage();
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage));
}
});*/
}
void retry() {
loadInitial(initialParams, initialCallback);
}
void retryLoadingMore() {
loadAfter(params, callback);
}
}

View File

@ -1,49 +0,0 @@
package ml.docilealligator.infinityforreddit;
import androidx.lifecycle.MutableLiveData;
import androidx.paging.DataSource;
import java.util.Locale;
import retrofit2.Retrofit;
public class CommentDataSourceFactory extends DataSource.Factory {
private Retrofit retrofit;
private Locale locale;
private String subredditNamePrefixed;
private String article;
private String comment;
private boolean isPost;
private CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback;
private CommentDataSource commentDataSource;
private MutableLiveData<CommentDataSource> commentDataSourceMutableLiveData;
CommentDataSourceFactory(Retrofit retrofit, Locale locale, String subredditNamePrefixed,
String article, String comment, boolean isPost,
CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback) {
this.retrofit = retrofit;
this.locale = locale;
this.subredditNamePrefixed = subredditNamePrefixed;
this.article = article;
this.comment = comment;
this.isPost = isPost;
commentDataSourceMutableLiveData = new MutableLiveData<>();
this.onCommentFetchedCallback = onCommentFetchedCallback;
}
@Override
public DataSource create() {
commentDataSource = new CommentDataSource(retrofit, locale, subredditNamePrefixed, article, comment, isPost, onCommentFetchedCallback);
commentDataSourceMutableLiveData.postValue(commentDataSource);
return commentDataSource;
}
public MutableLiveData<CommentDataSource> getCommentDataSourceMutableLiveData() {
return commentDataSourceMutableLiveData;
}
CommentDataSource getCommentDataSource() {
return commentDataSource;
}
}

View File

@ -604,6 +604,10 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
notifyItemChanged(mVisibleComments.size() + 1); notifyItemChanged(mVisibleComments.size() + 1);
} }
ArrayList<CommentData> getVisibleComments() {
return mVisibleComments;
}
@Override @Override
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
if (holder instanceof CommentViewHolder) { if (holder instanceof CommentViewHolder) {

View File

@ -1,90 +0,0 @@
package ml.docilealligator.infinityforreddit;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.paging.LivePagedListBuilder;
import androidx.paging.PagedList;
import androidx.annotation.NonNull;
import java.util.Locale;
import retrofit2.Retrofit;
public class CommentViewModel extends ViewModel {
private CommentDataSourceFactory commentDataSourceFactory;
private LiveData<NetworkState> paginationNetworkState;
private LiveData<NetworkState> initialLoadingState;
private LiveData<PagedList<CommentData>> comments;
public CommentViewModel(Retrofit retrofit, Locale locale, String subredditNamePrefixed,
String article, String comment, boolean isPost,
CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback) {
commentDataSourceFactory = new CommentDataSourceFactory(retrofit, locale, subredditNamePrefixed, article, comment, isPost, onCommentFetchedCallback);
initialLoadingState = Transformations.switchMap(commentDataSourceFactory.getCommentDataSourceMutableLiveData(),
dataSource -> dataSource.getInitialLoadStateLiveData());
paginationNetworkState = Transformations.switchMap(commentDataSourceFactory.getCommentDataSourceMutableLiveData(),
dataSource -> dataSource.getPaginationNetworkStateLiveData());
PagedList.Config pagedListConfig =
(new PagedList.Config.Builder())
.setEnablePlaceholders(false)
.setPageSize(25)
.build();
comments = (new LivePagedListBuilder(commentDataSourceFactory, pagedListConfig)).build();
}
LiveData<PagedList<CommentData>> getComments() {
return comments;
}
LiveData<NetworkState> getPaginationNetworkState() {
return paginationNetworkState;
}
LiveData<NetworkState> getInitialLoadingState() {
return initialLoadingState;
}
void refresh() {
commentDataSourceFactory.getCommentDataSource().invalidate();
}
void retry() {
commentDataSourceFactory.getCommentDataSource().retry();
}
void retryLoadingMore() {
commentDataSourceFactory.getCommentDataSource().retryLoadingMore();
}
public static class Factory extends ViewModelProvider.NewInstanceFactory {
private Retrofit retrofit;
private Locale locale;
private String subredditNamePrefixed;
private String article;
private String comment;
private boolean isPost;
private CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback;
public Factory(Retrofit retrofit, Locale locale, String subredditNamePrefixed,
String article, String comment, boolean isPost,
CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback) {
this.retrofit = retrofit;
this.locale = locale;
this.subredditNamePrefixed = subredditNamePrefixed;
this.article = article;
this.comment = comment;
this.isPost = isPost;
this.onCommentFetchedCallback = onCommentFetchedCallback;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return (T) new CommentViewModel(retrofit, locale, subredditNamePrefixed, article, comment, isPost, onCommentFetchedCallback);
}
}
}

View File

@ -49,6 +49,11 @@ public class ViewPostDetailActivity extends AppCompatActivity {
private static final String ORIENTATION_STATE = "OS"; private static final String ORIENTATION_STATE = "OS";
private static final String POST_STATE = "PS"; private static final String POST_STATE = "PS";
private static final String IS_REFRESHING_STATE = "IRS"; private static final String IS_REFRESHING_STATE = "IRS";
private static final String IS_LOADING_MORE_CHILDREN_STATE = "ILMCS";
private static final String COMMENTS_STATE = "CS";
private static final String HAS_MORE_CHILDREN_STATE = "HMCS";
private static final String MORE_CHILDREN_LIST_STATE = "MCLS";
private static final String MORE_CHILDREN_STARTING_INDEX_STATE = "MCSIS";
private Post mPost; private Post mPost;
private int postListPosition = -1; private int postListPosition = -1;
@ -58,6 +63,7 @@ public class ViewPostDetailActivity extends AppCompatActivity {
private ArrayList<String> children; private ArrayList<String> children;
private int mChildrenStartingIndex = 0; private int mChildrenStartingIndex = 0;
private boolean loadMoreChildrenSuccess = true; private boolean loadMoreChildrenSuccess = true;
private boolean hasMoreChildren;
private LinearLayoutManager mLinearLayoutManager; private LinearLayoutManager mLinearLayoutManager;
private CommentRecyclerViewAdapter mAdapter; private CommentRecyclerViewAdapter mAdapter;
@ -128,14 +134,24 @@ public class ViewPostDetailActivity extends AppCompatActivity {
if(isRefreshing) { if(isRefreshing) {
isRefreshing = false; isRefreshing = false;
refresh(); refresh();
} else {
mAdapter.addComments(savedInstanceState.getParcelableArrayList(COMMENTS_STATE),
savedInstanceState.getBoolean(HAS_MORE_CHILDREN_STATE));
isLoadingMoreChildren = savedInstanceState.getBoolean(IS_LOADING_MORE_CHILDREN_STATE);
children = savedInstanceState.getStringArrayList(MORE_CHILDREN_LIST_STATE);
mChildrenStartingIndex = savedInstanceState.getInt(MORE_CHILDREN_STARTING_INDEX_STATE);
if(isLoadingMoreChildren) {
isLoadingMoreChildren = false;
fetchMoreComments();
} }
} }
} else {
fetchComment();
}
if(getIntent().hasExtra(EXTRA_POST_LIST_POSITION)) { if(getIntent().hasExtra(EXTRA_POST_LIST_POSITION)) {
postListPosition = getIntent().getExtras().getInt(EXTRA_POST_LIST_POSITION); postListPosition = getIntent().getExtras().getInt(EXTRA_POST_LIST_POSITION);
} }
fetchComment();
} }
private void fetchComment() { private void fetchComment() {
@ -148,7 +164,8 @@ public class ViewPostDetailActivity extends AppCompatActivity {
String parentId, ArrayList<String> children) { String parentId, ArrayList<String> children) {
ViewPostDetailActivity.this.children = children; ViewPostDetailActivity.this.children = children;
mAdapter.addComments(expandedComments, children.size() != 0); hasMoreChildren = children.size() != 0;
mAdapter.addComments(expandedComments, hasMoreChildren);
if(children.size() > 0) { if(children.size() > 0) {
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@ -219,7 +236,8 @@ public class ViewPostDetailActivity extends AppCompatActivity {
0, mLocale, new FetchComment.FetchMoreCommentListener() { 0, mLocale, new FetchComment.FetchMoreCommentListener() {
@Override @Override
public void onFetchMoreCommentSuccess(ArrayList<CommentData> expandedComments, int childrenStartingIndex) { public void onFetchMoreCommentSuccess(ArrayList<CommentData> expandedComments, int childrenStartingIndex) {
mAdapter.addComments(expandedComments, childrenStartingIndex < children.size()); hasMoreChildren = childrenStartingIndex < children.size();
mAdapter.addComments(expandedComments, hasMoreChildren);
mChildrenStartingIndex = childrenStartingIndex; mChildrenStartingIndex = childrenStartingIndex;
isLoadingMoreChildren = false; isLoadingMoreChildren = false;
loadMoreChildrenSuccess = true; loadMoreChildrenSuccess = true;
@ -322,6 +340,11 @@ public class ViewPostDetailActivity extends AppCompatActivity {
outState.putInt(ORIENTATION_STATE, orientation); outState.putInt(ORIENTATION_STATE, orientation);
outState.putParcelable(POST_STATE, mPost); outState.putParcelable(POST_STATE, mPost);
outState.putBoolean(IS_REFRESHING_STATE, isRefreshing); outState.putBoolean(IS_REFRESHING_STATE, isRefreshing);
outState.putBoolean(IS_LOADING_MORE_CHILDREN_STATE, isLoadingMoreChildren);
outState.putParcelableArrayList(COMMENTS_STATE, mAdapter.getVisibleComments());
outState.putBoolean(HAS_MORE_CHILDREN_STATE, hasMoreChildren);
outState.putStringArrayList(MORE_CHILDREN_LIST_STATE, children);
outState.putInt(MORE_CHILDREN_STARTING_INDEX_STATE, mChildrenStartingIndex);
} }
@Override @Override