Use Retrofit to fetch posts. Delete PaginationRequestQueueSynchronizer because there is no need to pass request queue between PostFragment and PostPaginationScrollListener. Delete and rewrite some code.

This commit is contained in:
Alex Ning 2018-08-29 12:54:05 +08:00
parent 2a57e4d5b4
commit 3fa6257428
9 changed files with 245 additions and 334 deletions

View File

@ -5,7 +5,6 @@ import android.arch.lifecycle.ViewModelProviders;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -32,6 +31,8 @@ import de.hdodenhof.circleimageview.CircleImageView;
public class MainActivity extends AppCompatActivity { public class MainActivity extends AppCompatActivity {
private static final String FRAGMENT_OUT_STATE_KEY = "FOSK";
private String nameState = "NS"; private String nameState = "NS";
private String profileImageUrlState = "PIUS"; private String profileImageUrlState = "PIUS";
private String bannerImageUrlState = "BIUS"; private String bannerImageUrlState = "BIUS";
@ -77,16 +78,12 @@ public class MainActivity extends AppCompatActivity {
} else { } else {
if(savedInstanceState == null) { if(savedInstanceState == null) {
mFragment = new PostFragment(); mFragment = new PostFragment();
Uri uri = Uri.parse(RedditUtils.OAUTH_API_BASE_URI + RedditUtils.BEST_POST_SUFFIX)
.buildUpon().appendQueryParameter(RedditUtils.RAW_JSON_KEY, RedditUtils.RAW_JSON_VALUE)
.build();
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString(PostFragment.QUERY_POST_URL_KEY, uri.toString());
bundle.putBoolean(PostFragment.IS_BEST_POST_KEY, true); bundle.putBoolean(PostFragment.IS_BEST_POST_KEY, true);
mFragment.setArguments(bundle); mFragment.setArguments(bundle);
getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_content_main, mFragment).commit(); getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_content_main, mFragment).commit();
} else { } else {
mFragment = getSupportFragmentManager().getFragment(savedInstanceState, "outStateFragment"); mFragment = getSupportFragmentManager().getFragment(savedInstanceState, FRAGMENT_OUT_STATE_KEY);
getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_content_main, mFragment).commit(); getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_content_main, mFragment).commit();
} }
@ -271,7 +268,7 @@ public class MainActivity extends AppCompatActivity {
protected void onSaveInstanceState(Bundle outState) { protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
if(mFragment != null) { if(mFragment != null) {
getSupportFragmentManager().putFragment(outState, "outStateFragment", mFragment); getSupportFragmentManager().putFragment(outState, FRAGMENT_OUT_STATE_KEY, mFragment);
} }
outState.putString(nameState, mName); outState.putString(nameState, mName);
outState.putString(profileImageUrlState, mProfileImageUrl); outState.putString(profileImageUrlState, mProfileImageUrl);

View File

@ -1,7 +0,0 @@
package ml.docilealligator.infinityforreddit;
import com.android.volley.RequestQueue;
interface PaginationRequestQueueSynchronizer {
void passQueue(RequestQueue q);
}

View File

@ -9,7 +9,6 @@ class PaginationSynchronizer implements Parcelable {
private PaginationNotifier paginationNotifier; private PaginationNotifier paginationNotifier;
private PaginationRetryNotifier paginationRetryNotifier; private PaginationRetryNotifier paginationRetryNotifier;
private LastItemSynchronizer lastItemSynchronizer; private LastItemSynchronizer lastItemSynchronizer;
private PaginationRequestQueueSynchronizer paginationRequestQueueSynchronizer;
PaginationSynchronizer() { PaginationSynchronizer() {
loadingState = false; loadingState = false;
@ -74,14 +73,6 @@ class PaginationSynchronizer implements Parcelable {
return lastItemSynchronizer; return lastItemSynchronizer;
} }
public void setPaginationRequestQueueSynchronizer(PaginationRequestQueueSynchronizer paginationRequestQueueSynchronizer) {
this.paginationRequestQueueSynchronizer = paginationRequestQueueSynchronizer;
}
public PaginationRequestQueueSynchronizer getPaginationRequestQueueSynchronizer() {
return paginationRequestQueueSynchronizer;
}
@Override @Override
public int describeContents() { public int describeContents() {
return 0; return 0;

View File

@ -4,7 +4,6 @@ package ml.docilealligator.infinityforreddit;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -20,16 +19,12 @@ import android.view.ViewGroup;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.Toast; import android.widget.Toast;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Retrofit;
import retrofit2.converter.scalars.ScalarsConverterFactory;
/** /**
@ -37,7 +32,7 @@ import java.util.Map;
*/ */
public class PostFragment extends Fragment { public class PostFragment extends Fragment {
static final String QUERY_POST_URL_KEY = "QPUK"; static final String SUBREDDIT_NAME_KEY = "SNK";
static final String IS_BEST_POST_KEY = "IBPK"; static final String IS_BEST_POST_KEY = "IBPK";
private CoordinatorLayout mCoordinatorLayout; private CoordinatorLayout mCoordinatorLayout;
@ -50,16 +45,11 @@ public class PostFragment extends Fragment {
private PostRecyclerViewAdapter mAdapter; private PostRecyclerViewAdapter mAdapter;
private boolean mIsBestPost; private boolean mIsBestPost;
private String mQueryPostUrl; private String mSubredditName;
private String PostDataParcelableState = "BPDPS"; private String PostDataParcelableState = "BPDPS";
private String lastItemState = "LIS"; private String lastItemState = "LIS";
private String paginationSynchronizerState = "PSS"; private String paginationSynchronizerState = "PSS";
private RequestQueue mRequestQueue;
private RequestQueue mPaginationRequestQueue;
private RequestQueue mAcquireAccessTokenRequestQueue;
private RequestQueue mVoteThingRequestQueue;
public PostFragment() { public PostFragment() {
// Required empty public constructor // Required empty public constructor
} }
@ -71,20 +61,19 @@ public class PostFragment extends Fragment {
if(savedInstanceState.containsKey(PostDataParcelableState)) { if(savedInstanceState.containsKey(PostDataParcelableState)) {
mPostData = savedInstanceState.getParcelableArrayList(PostDataParcelableState); mPostData = savedInstanceState.getParcelableArrayList(PostDataParcelableState);
mLastItem = savedInstanceState.getString(lastItemState); mLastItem = savedInstanceState.getString(lastItemState);
mAdapter = new PostRecyclerViewAdapter(getActivity(), mPostData, mPaginationSynchronizer, mVoteThingRequestQueue); mAdapter = new PostRecyclerViewAdapter(getActivity(), mPostData, mPaginationSynchronizer);
mPostRecyclerView.setAdapter(mAdapter); mPostRecyclerView.setAdapter(mAdapter);
mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener( mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener(
getActivity(), mLinearLayoutManager, mAdapter, mLastItem, mPostData, getActivity(), mLinearLayoutManager, mAdapter, mLastItem, mPostData,
mPaginationSynchronizer, mAcquireAccessTokenRequestQueue, mPaginationSynchronizer, mSubredditName, mIsBestPost,
mQueryPostUrl, mIsBestPost,
mPaginationSynchronizer.isLoading(), mPaginationSynchronizer.isLoadSuccess(), mPaginationSynchronizer.isLoading(), mPaginationSynchronizer.isLoadSuccess(),
getResources().getConfiguration().locale)); getResources().getConfiguration().locale));
mProgressBar.setVisibility(View.GONE); mProgressBar.setVisibility(View.GONE);
} else { } else {
if(mIsBestPost) { if(mIsBestPost) {
queryBestPost(1); fetchBestPost(1);
} else { } else {
fetchPost(mQueryPostUrl, 1); fetchPost(mSubredditName, 1);
} }
} }
} }
@ -94,22 +83,6 @@ public class PostFragment extends Fragment {
public void onSaveInstanceState(@NonNull Bundle outState) { public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
if(mRequestQueue != null) {
mRequestQueue.cancelAll(this);
}
if(mAcquireAccessTokenRequestQueue != null) {
mAcquireAccessTokenRequestQueue.cancelAll(RefreshAccessToken.class);
}
if(mVoteThingRequestQueue != null) {
mVoteThingRequestQueue.cancelAll(VoteThing.class);
}
if(mPaginationRequestQueue != null) {
mPaginationRequestQueue.cancelAll(PostPaginationScrollListener.class);
}
if(mPostData != null) { if(mPostData != null) {
outState.putParcelableArrayList(PostDataParcelableState, mPostData); outState.putParcelableArrayList(PostDataParcelableState, mPostData);
outState.putString(lastItemState, mLastItem); outState.putString(lastItemState, mLastItem);
@ -144,21 +117,19 @@ public class PostFragment extends Fragment {
} }
});*/ });*/
mRequestQueue = Volley.newRequestQueue(getActivity());
mAcquireAccessTokenRequestQueue = Volley.newRequestQueue(getActivity());
mVoteThingRequestQueue = Volley.newRequestQueue(getActivity());
mIsBestPost = getArguments().getBoolean(IS_BEST_POST_KEY); mIsBestPost = getArguments().getBoolean(IS_BEST_POST_KEY);
mQueryPostUrl = getArguments().getString(QUERY_POST_URL_KEY); if(!mIsBestPost) {
mSubredditName = getArguments().getString(SUBREDDIT_NAME_KEY);
}
if(savedInstanceState != null && savedInstanceState.getParcelable(paginationSynchronizerState) != null) { if(savedInstanceState != null && savedInstanceState.getParcelable(paginationSynchronizerState) != null) {
mPaginationSynchronizer = savedInstanceState.getParcelable(paginationSynchronizerState); mPaginationSynchronizer = savedInstanceState.getParcelable(paginationSynchronizerState);
} else { } else {
mPaginationSynchronizer = new PaginationSynchronizer(); mPaginationSynchronizer = new PaginationSynchronizer();
if(mIsBestPost) { if(mIsBestPost) {
queryBestPost(1); fetchBestPost(1);
} else { } else {
fetchPost(mQueryPostUrl, 1); fetchPost(mSubredditName, 1);
} }
} }
@ -170,18 +141,10 @@ public class PostFragment extends Fragment {
}; };
mPaginationSynchronizer.setLastItemSynchronizer(lastItemSynchronizer); mPaginationSynchronizer.setLastItemSynchronizer(lastItemSynchronizer);
PaginationRequestQueueSynchronizer paginationRequestQueueSynchronizer = new PaginationRequestQueueSynchronizer() {
@Override
public void passQueue(RequestQueue q) {
mPaginationRequestQueue = q;
}
};
mPaginationSynchronizer.setPaginationRequestQueueSynchronizer(paginationRequestQueueSynchronizer);
return rootView; return rootView;
} }
private void queryBestPost(final int refreshTime) { private void fetchBestPost(final int refreshTime) {
if(refreshTime < 0) { if(refreshTime < 0) {
showErrorSnackbar(); showErrorSnackbar();
return; return;
@ -189,27 +152,38 @@ public class PostFragment extends Fragment {
mProgressBar.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.VISIBLE);
StringRequest postRequest = new StringRequest(Request.Method.GET, mQueryPostUrl, new Response.Listener<String>() { Retrofit retrofit = new Retrofit.Builder()
.baseUrl(RedditUtils.OAUTH_API_BASE_URI)
.addConverterFactory(ScalarsConverterFactory.create())
.build();
RedditAPI api = retrofit.create(RedditAPI.class);
String accessToken = getActivity().getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE)
.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, "");
Call<String> bestPost = api.getBestPost(mLastItem, RedditUtils.getOAuthHeader(accessToken));
bestPost.enqueue(new Callback<String>() {
@Override @Override
public void onResponse(String response) { public void onResponse(Call<String> call, retrofit2.Response<String> response) {
if(getActivity() != null) { if(getActivity() != null) {
if(response.isSuccessful()) {
ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("response", response); ClipData clip = ClipData.newPlainText("response", response.body());
clipboard.setPrimaryClip(clip); clipboard.setPrimaryClip(clip);
//new ParsePostDataAsyncTask(response, accessToken).execute();
ParsePost.parsePost(response, new ArrayList<PostData>(), ParsePost.parsePost(response.body(), new ArrayList<PostData>(),
getResources().getConfiguration().locale, new ParsePost.ParsePostListener() { getResources().getConfiguration().locale, new ParsePost.ParsePostListener() {
@Override @Override
public void onParsePostSuccess(ArrayList<PostData> postData, String lastItem) { public void onParsePostSuccess(ArrayList<PostData> postData, String lastItem) {
mPostData = postData; mPostData = postData;
mLastItem = lastItem; mLastItem = lastItem;
mAdapter = new PostRecyclerViewAdapter(getActivity(), postData, mPaginationSynchronizer, mVoteThingRequestQueue); mAdapter = new PostRecyclerViewAdapter(getActivity(), postData, mPaginationSynchronizer);
mPostRecyclerView.setAdapter(mAdapter); mPostRecyclerView.setAdapter(mAdapter);
mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener( mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener(
getActivity(), mLinearLayoutManager, mAdapter, lastItem, postData, getActivity(), mLinearLayoutManager, mAdapter, lastItem, postData,
mPaginationSynchronizer, mAcquireAccessTokenRequestQueue, mPaginationSynchronizer, mSubredditName, mIsBestPost,
mQueryPostUrl, mIsBestPost,
mPaginationSynchronizer.isLoading(), mPaginationSynchronizer.isLoadSuccess(), mPaginationSynchronizer.isLoading(), mPaginationSynchronizer.isLoadSuccess(),
getResources().getConfiguration().locale)); getResources().getConfiguration().locale));
mProgressBar.setVisibility(View.GONE); mProgressBar.setVisibility(View.GONE);
@ -222,38 +196,31 @@ public class PostFragment extends Fragment {
mProgressBar.setVisibility(View.GONE); mProgressBar.setVisibility(View.GONE);
} }
}); });
} } else if(response.code() == 401) {
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
if (error instanceof AuthFailureError) {
// Error indicating that there was an Authentication Failure while performing the request // Error indicating that there was an Authentication Failure while performing the request
// Access token expired // Access token expired
RefreshAccessToken.refreshAccessToken(getActivity(), RefreshAccessToken.refreshAccessToken(getActivity(),
new RefreshAccessToken.RefreshAccessTokenListener() { new RefreshAccessToken.RefreshAccessTokenListener() {
@Override @Override
public void onRefreshAccessTokenSuccess() { public void onRefreshAccessTokenSuccess() {
queryBestPost(refreshTime - 1); fetchBestPost(refreshTime - 1);
} }
@Override @Override
public void onRefreshAccessTokenFail() {} public void onRefreshAccessTokenFail() {}
}); });
} else { } else {
Log.i("Post fetch error", error.toString()); Log.i("Post fetch error", response.message());
showErrorSnackbar(); showErrorSnackbar();
} }
} }
}) {
@Override
public Map<String, String> getHeaders() {
String accessToken = getActivity().getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE).getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, "");
return RedditUtils.getOAuthHeader(accessToken);
} }
};
postRequest.setTag(PostFragment.class); @Override
mRequestQueue.add(postRequest); public void onFailure(Call<String> call, Throwable t) {
showErrorSnackbar();
}
});
} }
private void fetchPost(final String queryPostUrl, final int refreshTime) { private void fetchPost(final String queryPostUrl, final int refreshTime) {
@ -264,31 +231,35 @@ public class PostFragment extends Fragment {
mProgressBar.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.VISIBLE);
Uri uri = Uri.parse(RedditUtils.OAUTH_API_BASE_URI + RedditUtils.BEST_POST_SUFFIX) Retrofit retrofit = new Retrofit.Builder()
.buildUpon().appendQueryParameter(RedditUtils.RAW_JSON_KEY, RedditUtils.RAW_JSON_VALUE) .baseUrl(RedditUtils.API_BASE_URI)
.addConverterFactory(ScalarsConverterFactory.create())
.build(); .build();
StringRequest postRequest = new StringRequest(Request.Method.GET, queryPostUrl, new Response.Listener<String>() { RedditAPI api = retrofit.create(RedditAPI.class);
Call<String> getPost = api.getPost(mSubredditName, mLastItem);
getPost.enqueue(new Callback<String>() {
@Override @Override
public void onResponse(String response) { public void onResponse(Call<String> call, retrofit2.Response<String> response) {
if(getActivity() != null) { if(getActivity() != null) {
Log.i("response_code", Integer.toString(response.code()));
if(response.isSuccessful()) {
ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("response", response); ClipData clip = ClipData.newPlainText("response", response.body());
clipboard.setPrimaryClip(clip); clipboard.setPrimaryClip(clip);
//new ParsePostDataAsyncTask(response, accessToken).execute();
ParsePost.parsePost(response, new ArrayList<PostData>(), ParsePost.parsePost(response.body(), new ArrayList<PostData>(),
getResources().getConfiguration().locale, new ParsePost.ParsePostListener() { getResources().getConfiguration().locale, new ParsePost.ParsePostListener() {
@Override @Override
public void onParsePostSuccess(ArrayList<PostData> postData, String lastItem) { public void onParsePostSuccess(ArrayList<PostData> postData, String lastItem) {
mPostData = postData; mPostData = postData;
mLastItem = lastItem; mLastItem = lastItem;
mAdapter = new PostRecyclerViewAdapter(getActivity(), postData, mPaginationSynchronizer, mVoteThingRequestQueue); mAdapter = new PostRecyclerViewAdapter(getActivity(), postData, mPaginationSynchronizer);
mPostRecyclerView.setAdapter(mAdapter); mPostRecyclerView.setAdapter(mAdapter);
mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener( mPostRecyclerView.addOnScrollListener(new PostPaginationScrollListener(
getActivity(), mLinearLayoutManager, mAdapter, lastItem, postData, getActivity(), mLinearLayoutManager, mAdapter, lastItem, postData,
mPaginationSynchronizer, mAcquireAccessTokenRequestQueue, mPaginationSynchronizer, mSubredditName, mIsBestPost,
mQueryPostUrl, mIsBestPost,
mPaginationSynchronizer.isLoading(), mPaginationSynchronizer.isLoadSuccess(), mPaginationSynchronizer.isLoading(), mPaginationSynchronizer.isLoadSuccess(),
getResources().getConfiguration().locale)); getResources().getConfiguration().locale));
mProgressBar.setVisibility(View.GONE); mProgressBar.setVisibility(View.GONE);
@ -301,32 +272,18 @@ public class PostFragment extends Fragment {
mProgressBar.setVisibility(View.GONE); mProgressBar.setVisibility(View.GONE);
} }
}); });
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
if (error instanceof AuthFailureError) {
// Error indicating that there was an Authentication Failure while performing the request
// Access token expired
RefreshAccessToken.refreshAccessToken(getActivity(),
new RefreshAccessToken.RefreshAccessTokenListener() {
@Override
public void onRefreshAccessTokenSuccess() {
fetchPost(queryPostUrl, refreshTime - 1);
}
@Override
public void onRefreshAccessTokenFail() {}
});
} else { } else {
Log.i("Post fetch error", error.toString()); Log.i("Post fetch error", response.message());
showErrorSnackbar(); showErrorSnackbar();
} }
} }
}
@Override
public void onFailure(Call<String> call, Throwable t) {
showErrorSnackbar();
}
}); });
postRequest.setTag(PostFragment.class);
mRequestQueue.add(postRequest);
} }
private void showErrorSnackbar() { private void showErrorSnackbar() {
@ -336,9 +293,9 @@ public class PostFragment extends Fragment {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
if(mIsBestPost) { if(mIsBestPost) {
queryBestPost(1); fetchBestPost(1);
} else { } else {
fetchPost(mQueryPostUrl, 1); fetchPost(mSubredditName, 1);
} }
} }
}); });

View File

@ -3,24 +3,19 @@ package ml.docilealligator.infinityforreddit;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.net.Uri;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Retrofit;
import retrofit2.converter.scalars.ScalarsConverterFactory;
/** /**
* Created by alex on 3/12/18. * Created by alex on 3/12/18.
@ -34,21 +29,18 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener {
private PaginationSynchronizer mPaginationSynchronizer; private PaginationSynchronizer mPaginationSynchronizer;
private PaginationRetryNotifier mPaginationRetryNotifier; private PaginationRetryNotifier mPaginationRetryNotifier;
private LastItemSynchronizer mLastItemSynchronizer; private LastItemSynchronizer mLastItemSynchronizer;
private PaginationRequestQueueSynchronizer mPaginationRequestQueueSynchronizer;
private String mQueryPostUrl; private String mSubredditName;
private boolean isBestPost; private boolean isBestPost;
private boolean isLoading; private boolean isLoading;
private boolean loadSuccess; private boolean loadSuccess;
private Locale locale; private Locale locale;
private String mLastItem; private String mLastItem;
private RequestQueue mRequestQueue;
private RequestQueue mAcquireAccessTokenRequestQueue;
PostPaginationScrollListener(Context context, LinearLayoutManager layoutManager, PostRecyclerViewAdapter adapter, PostPaginationScrollListener(Context context, LinearLayoutManager layoutManager, PostRecyclerViewAdapter adapter,
String lastItem, ArrayList<PostData> postData, PaginationSynchronizer paginationSynchronizer, String lastItem, ArrayList<PostData> postData, PaginationSynchronizer paginationSynchronizer,
RequestQueue acquireAccessTokenRequestQueue, final String queryPostUrl, final String subredditName, final boolean isBestPost, boolean isLoading,
final boolean isBestPost, boolean isLoading, boolean loadSuccess, Locale locale) { boolean loadSuccess, Locale locale) {
if(context != null) { if(context != null) {
this.mContext = context; this.mContext = context;
this.mLayoutManager = layoutManager; this.mLayoutManager = layoutManager;
@ -56,29 +48,24 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener {
this.mLastItem = lastItem; this.mLastItem = lastItem;
this.mPostData = postData; this.mPostData = postData;
this.mPaginationSynchronizer = paginationSynchronizer; this.mPaginationSynchronizer = paginationSynchronizer;
this.mAcquireAccessTokenRequestQueue = acquireAccessTokenRequestQueue; this.mSubredditName = subredditName;
this.mQueryPostUrl = queryPostUrl;
this.isBestPost = isBestPost; this.isBestPost = isBestPost;
this.isLoading = isLoading; this.isLoading = isLoading;
this.loadSuccess = loadSuccess; this.loadSuccess = loadSuccess;
this.locale = locale; this.locale = locale;
mRequestQueue = Volley.newRequestQueue(mContext);
mAcquireAccessTokenRequestQueue = Volley.newRequestQueue(mContext);
mPaginationRetryNotifier = new PaginationRetryNotifier() { mPaginationRetryNotifier = new PaginationRetryNotifier() {
@Override @Override
public void retry() { public void retry() {
if(isBestPost) { if(isBestPost) {
fetchBestPost(queryPostUrl, 1); fetchBestPost(1);
} else { } else {
fetchPost(queryPostUrl, 1); fetchPost(subredditName, 1);
} }
} }
}; };
mPaginationSynchronizer.setPaginationRetryNotifier(mPaginationRetryNotifier); mPaginationSynchronizer.setPaginationRetryNotifier(mPaginationRetryNotifier);
mLastItemSynchronizer = mPaginationSynchronizer.getLastItemSynchronizer(); mLastItemSynchronizer = mPaginationSynchronizer.getLastItemSynchronizer();
mPaginationRequestQueueSynchronizer = mPaginationSynchronizer.getPaginationRequestQueueSynchronizer();
mPaginationRequestQueueSynchronizer.passQueue(mRequestQueue);
} }
} }
@ -92,16 +79,16 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener {
if((visibleItemCount + firstVisibleItemPosition >= totalItemCount) && firstVisibleItemPosition >= 0) { if((visibleItemCount + firstVisibleItemPosition >= totalItemCount) && firstVisibleItemPosition >= 0) {
if(isBestPost) { if(isBestPost) {
fetchBestPost(mQueryPostUrl, 1); fetchBestPost(1);
} else { } else {
fetchPost(mQueryPostUrl, 1); fetchPost(mSubredditName, 1);
} }
} }
} }
} }
private void fetchBestPost(final String queryPostUrl, final int refreshTime) { private void fetchBestPost(final int refreshTime) {
if(refreshTime < 0) { if(refreshTime < 0) {
loadFailed(); loadFailed();
return; return;
@ -111,16 +98,24 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener {
loadSuccess = false; loadSuccess = false;
mPaginationSynchronizer.setLoading(true); mPaginationSynchronizer.setLoading(true);
Uri uri = Uri.parse(queryPostUrl) Retrofit retrofit = new Retrofit.Builder()
.buildUpon().appendQueryParameter(RedditUtils.AFTER_KEY, mLastItem).build(); .baseUrl(RedditUtils.OAUTH_API_BASE_URI)
.addConverterFactory(ScalarsConverterFactory.create())
.build();
StringRequest bestPostRequest = new StringRequest(Request.Method.GET, uri.toString(), new Response.Listener<String>() { RedditAPI api = retrofit.create(RedditAPI.class);
String accessToken = mContext.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE)
.getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, "");
Call<String> bestPost = api.getBestPost(mLastItem, RedditUtils.getOAuthHeader(accessToken));
bestPost.enqueue(new Callback<String>() {
@Override @Override
public void onResponse(String response) { public void onResponse(Call<String> call, retrofit2.Response<String> response) {
if(response.isSuccessful()) {
ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("response", response); ClipData clip = ClipData.newPlainText("response", response.body());
clipboard.setPrimaryClip(clip); clipboard.setPrimaryClip(clip);
ParsePost.parsePost(response, mPostData, locale, new ParsePost.ParsePostListener() { ParsePost.parsePost(response.body(), mPostData, locale, new ParsePost.ParsePostListener() {
@Override @Override
public void onParsePostSuccess(ArrayList<PostData> bestPostData, String lastItem) { public void onParsePostSuccess(ArrayList<PostData> bestPostData, String lastItem) {
mAdapter.notifyDataSetChanged(); mAdapter.notifyDataSetChanged();
@ -140,17 +135,13 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener {
loadFailed(); loadFailed();
} }
}); });
} } else if(response.code() == 401) {
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
if (error instanceof AuthFailureError) {
//Access token expired //Access token expired
RefreshAccessToken.refreshAccessToken(mContext, RefreshAccessToken.refreshAccessToken(mContext,
new RefreshAccessToken.RefreshAccessTokenListener() { new RefreshAccessToken.RefreshAccessTokenListener() {
@Override @Override
public void onRefreshAccessTokenSuccess() { public void onRefreshAccessTokenSuccess() {
fetchBestPost(queryPostUrl, refreshTime - 1); fetchBestPost(refreshTime - 1);
} }
@Override @Override
@ -159,22 +150,19 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener {
}); });
} else { } else {
Toast.makeText(mContext, "Error getting best post", Toast.LENGTH_SHORT).show(); Toast.makeText(mContext, "Error getting best post", Toast.LENGTH_SHORT).show();
Log.i("best post", error.toString()); Log.i("best post", response.message());
loadFailed(); loadFailed();
} }
} }
}) {
@Override @Override
public Map<String, String> getHeaders() { public void onFailure(Call<String> call, Throwable t) {
String accessToken = mContext.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE).getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); loadFailed();
return RedditUtils.getOAuthHeader(accessToken);
} }
}; });
bestPostRequest.setTag(PostPaginationScrollListener.class);
mRequestQueue.add(bestPostRequest);
} }
private void fetchPost(final String queryPostUrl, final int refreshTime) { private void fetchPost(final String subredditName, final int refreshTime) {
if(refreshTime < 0) { if(refreshTime < 0) {
loadFailed(); loadFailed();
return; return;
@ -184,16 +172,21 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener {
loadSuccess = false; loadSuccess = false;
mPaginationSynchronizer.setLoading(true); mPaginationSynchronizer.setLoading(true);
Uri uri = Uri.parse(queryPostUrl) Retrofit retrofit = new Retrofit.Builder()
.buildUpon().appendQueryParameter(RedditUtils.AFTER_KEY, mLastItem).build(); .baseUrl(RedditUtils.API_BASE_URI)
.addConverterFactory(ScalarsConverterFactory.create())
.build();
StringRequest bestPostRequest = new StringRequest(Request.Method.GET, uri.toString(), new Response.Listener<String>() { RedditAPI api = retrofit.create(RedditAPI.class);
Call<String> getPost = api.getPost(subredditName, mLastItem);
getPost.enqueue(new Callback<String>() {
@Override @Override
public void onResponse(String response) { public void onResponse(Call<String> call, retrofit2.Response<String> response) {
if(response.isSuccessful()) {
ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("response", response); ClipData clip = ClipData.newPlainText("response", response.body());
clipboard.setPrimaryClip(clip); clipboard.setPrimaryClip(clip);
ParsePost.parsePost(response, mPostData, locale, new ParsePost.ParsePostListener() { ParsePost.parsePost(response.body(), mPostData, locale, new ParsePost.ParsePostListener() {
@Override @Override
public void onParsePostSuccess(ArrayList<PostData> bestPostData, String lastItem) { public void onParsePostSuccess(ArrayList<PostData> bestPostData, String lastItem) {
mAdapter.notifyDataSetChanged(); mAdapter.notifyDataSetChanged();
@ -213,32 +206,19 @@ class PostPaginationScrollListener extends RecyclerView.OnScrollListener {
loadFailed(); loadFailed();
} }
}); });
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
if (error instanceof AuthFailureError) {
//Access token expired
RefreshAccessToken.refreshAccessToken(mContext,
new RefreshAccessToken.RefreshAccessTokenListener() {
@Override
public void onRefreshAccessTokenSuccess() {
fetchPost(queryPostUrl, refreshTime - 1);
}
@Override
public void onRefreshAccessTokenFail() {
}
});
} else { } else {
Toast.makeText(mContext, "Error getting best post", Toast.LENGTH_SHORT).show(); Toast.makeText(mContext, "Error getting best post", Toast.LENGTH_SHORT).show();
Log.i("best post", error.toString()); Log.i("best post", response.message());
loadFailed(); loadFailed();
} }
} }
@Override
public void onFailure(Call<String> call, Throwable t) {
Toast.makeText(mContext, "Error getting best post", Toast.LENGTH_SHORT).show();
loadFailed();
}
}); });
bestPostRequest.setTag(PostPaginationScrollListener.class);
mRequestQueue.add(bestPostRequest);
} }
private void loadFailed() { private void loadFailed() {

View File

@ -23,7 +23,6 @@ import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.android.volley.RequestQueue;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager; import com.bumptech.glide.RequestManager;
import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.DataSource;
@ -43,7 +42,6 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
private ArrayList<PostData> mPostData; private ArrayList<PostData> mPostData;
private Context mContext; private Context mContext;
private PaginationSynchronizer mPaginationSynchronizer; private PaginationSynchronizer mPaginationSynchronizer;
private RequestQueue mVoteThingRequestQueue;
private RequestManager glide; private RequestManager glide;
private SubredditDao subredditDao; private SubredditDao subredditDao;
private boolean isLoadingMorePostSuccess; private boolean isLoadingMorePostSuccess;
@ -53,13 +51,11 @@ class PostRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
private static final int VIEW_TYPE_LOADING = 1; private static final int VIEW_TYPE_LOADING = 1;
PostRecyclerViewAdapter(Context context, ArrayList<PostData> postData, PaginationSynchronizer paginationSynchronizer, PostRecyclerViewAdapter(Context context, ArrayList<PostData> postData, PaginationSynchronizer paginationSynchronizer) {
RequestQueue voteThingRequestQueue) {
if(context != null) { if(context != null) {
mContext = context; mContext = context;
mPostData = postData; mPostData = postData;
mPaginationSynchronizer = paginationSynchronizer; mPaginationSynchronizer = paginationSynchronizer;
mVoteThingRequestQueue = voteThingRequestQueue;
isLoadingMorePostSuccess = true; isLoadingMorePostSuccess = true;
canStartActivity = true; canStartActivity = true;
glide = Glide.with(mContext); glide = Glide.with(mContext);

View File

@ -31,4 +31,10 @@ public interface RedditAPI {
@FormUrlEncoded @FormUrlEncoded
@POST("api/vote") @POST("api/vote")
Call<String> voteThing(@HeaderMap Map<String, String> headers, @FieldMap Map<String, String> params); Call<String> voteThing(@HeaderMap Map<String, String> headers, @FieldMap Map<String, String> params);
@GET("best?raw_json=1")
Call<String> getBestPost(@Query("after") String lastItem, @HeaderMap Map<String, String> headers);
@GET("r/{subredditName}.json?raw_json=1")
Call<String> getPost(@Path("subredditName") String subredditName, @Query("after") String lastItem);
} }

View File

@ -13,9 +13,6 @@ class RedditUtils {
static final String OAUTH_URL ="https://www.reddit.com/api/v1/authorize.compact"; static final String OAUTH_URL ="https://www.reddit.com/api/v1/authorize.compact";
static final String OAUTH_API_BASE_URI = "https://oauth.reddit.com"; static final String OAUTH_API_BASE_URI = "https://oauth.reddit.com";
static final String API_BASE_URI = "https://www.reddit.com"; static final String API_BASE_URI = "https://www.reddit.com";
static final String RAW_JSON_KEY ="raw_json";
static final String RAW_JSON_VALUE = "1";
static final String BEST_POST_SUFFIX = "/best";
static final String CLIENT_ID_KEY = "client_id"; static final String CLIENT_ID_KEY = "client_id";
static final String CLIENT_ID = ""; static final String CLIENT_ID = "";
@ -49,8 +46,6 @@ class RedditUtils {
static final String DIR_DOWNVOTE = "-1"; static final String DIR_DOWNVOTE = "-1";
static final String RANK = "10"; static final String RANK = "10";
static final String AFTER_KEY = "after";
static Map<String, String> getHttpBasicAuthHeader() { static Map<String, String> getHttpBasicAuthHeader() {
Map<String, String> params = new HashMap<>(); Map<String, String> params = new HashMap<>();
String credentials = String.format("%s:%s", RedditUtils.CLIENT_ID, ""); String credentials = String.format("%s:%s", RedditUtils.CLIENT_ID, "");

View File

@ -3,7 +3,6 @@ package ml.docilealligator.infinityforreddit;
import android.arch.lifecycle.Observer; import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders; import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -165,11 +164,8 @@ public class ViewSubredditDetailActivity extends AppCompatActivity {
if(savedInstanceState == null) { if(savedInstanceState == null) {
mFragment = new PostFragment(); mFragment = new PostFragment();
Uri uri = Uri.parse(RedditUtils.getQuerySubredditPostUrl(subredditName))
.buildUpon().appendQueryParameter(RedditUtils.RAW_JSON_KEY, RedditUtils.RAW_JSON_VALUE)
.build();
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString(PostFragment.QUERY_POST_URL_KEY, uri.toString()); bundle.putString(PostFragment.SUBREDDIT_NAME_KEY, subredditName);
bundle.putBoolean(PostFragment.IS_BEST_POST_KEY, false); bundle.putBoolean(PostFragment.IS_BEST_POST_KEY, false);
mFragment.setArguments(bundle); mFragment.setArguments(bundle);
getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_view_subreddit_detail_activity, mFragment).commit(); getSupportFragmentManager().beginTransaction().replace(R.id.frame_layout_view_subreddit_detail_activity, mFragment).commit();