I would love your input: Paging Challenge

Here is my solution. In FlickrFetchr.fetchItems I changed the signature to take a page number as a parameter like this:

 public List<GalleryItem> fetchItems(int page) {
    List<GalleryItem> items = new ArrayList<>();
    try {
        String url = Uri.parse("https://api.flickr.com/services/rest/")
                .buildUpon()
                .appendQueryParameter("method", "flickr.photos.getRecent")
                .appendQueryParameter("api_key", API_KEY)
                .appendQueryParameter("format", "json")
                .appendQueryParameter("nojsoncallback", "1")
                .appendQueryParameter("extras", "url_s")
                .appendQueryParameter("page", String.valueOf(page))
                .build().toString();
        String jsonString = getUrlString(url);
        Log.i(TAG, "Recieved JSON: " + jsonString);
        JSONObject jsonBody = new JSONObject(jsonString);
        parseItems(items, jsonBody);
    } catch (IOException e) {
        Log.e(TAG, "Failed to fetch items", e);
    } catch (JSONException e) {
        Log.e(TAG, "Failed to parse JSON", e);
    }
    return items;
}

Then I created a member variable ‘mPage’ at the top of the fragment to keep track of it. I also have a member variable to hold the GridLayoutManager. This allowed me to create an OnScrollListener at the bottom of the Fragment class.

RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        // check if we are scrolling down
        if (dy > 0) {
            if (mGridLayoutManager.findLastVisibleItemPosition() > 80 * mPage){
                new FetchItemsTask().execute(mPage++);
            }
        }
    }
};

Once the GridLayoutManager gets to position 80 ( a little before the end of the list) I fetch another page by calling new FetchItemsTask().execute(mPage++) incrementing the page variable and also multiplying the position and the page number (ex. 80 * mPage) to make sure the requirement for fetching more data increases with the page number. A better algorithm for accomplishing this is out there but I didn’t want to spend too much time on this. The one problem that would arise is this; As more and more pages are added to the list, the difference between the LastVisibleItemPosition() and the actual end of the list will grow, triggering a FetchItems task a bit earlier each time.

To make this all work I had to also change the signature of the AsyncTask to accept an Integer object as input. I then pull it out in doInBackground and the list is appended in onPostExecute:

 private class FetchItemsTask extends AsyncTask<Integer, Void, List<GalleryItem>> {
    @Override
    protected List<GalleryItem> doInBackground(Integer... pageNum) {
        return new FlickrFetchr().fetchItems(pageNum[0]);
    }

    @Override
    protected void onPostExecute(List<GalleryItem> galleryItems) {
        mItems.addAll(galleryItems);
        setupAdapter();
    }
}
1 Like