RecyclerView Pagination Using AsyncTask Making Dup

2019-09-15 03:21发布

问题:

I have a gallery application that is parsing the Reddit API and populating a recyclerview list with images. Each page contains 25 pictures from that subreddit. But this code is making duplicate data calls which puts the same pages in the gallery when you scroll 2 or 3 times before it get the next page. How would I be able to fix this problem?

 public class DesktopGalleryFragment extends Fragment{
    private int count;
    private RecyclerView mDesktopRecyclerView;
    private List<DesktopItems> mList = new ArrayList<>();
    private String after, nullString;
    private Parcelable recyclerViewState;

    public String getAfter(String s){
        return this.after = s;
    }

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
        new FetchItemsTask().execute(nullString);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        mDesktopRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener(){
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState){

                PhotoAdapter adapter = (PhotoAdapter) recyclerView.getAdapter();
                int lastPostion = adapter.getLastBoundPosition();
                GridLayoutManager layoutManager = (GridLayoutManager) recyclerView.getLayoutManager();
                int loadBufferPosition = 1;
                if (lastPostion >= adapter.getItemCount() - layoutManager.getSpanCount() - loadBufferPosition){
                    new FetchItemsTask().execute(after);
                }
            }
        });

        return v;
    }

    private class FetchItemsTask extends AsyncTask<String, Void, List<DesktopItems>>{
        @Override
        protected List<DesktopItems> doInBackground(String... params){
            return new RedditParser().fetchItems(params[0]);
        }

        @Override
        protected void onPostExecute(List<DesktopItems> items){
            if (count > 1){
                getAfter(DesktopItems.getAfter());
                mList.addAll(items);
                mDesktopRecyclerView.getAdapter().notifyDataSetChanged();
            } else{
                mList = items;
                recyclerViewState = mDesktopRecyclerView.getLayoutManager().onSaveInstanceState();
                mDesktopRecyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);
                setupAdapter();
            }
            count++;
        }
    }
}

RedditParser.java

public List<DesktopItems> fetchItems(String after)
{
    List<DesktopItems> items = new ArrayList<>();
    int count = 0;
    int counter = count + 25;

    try
    {
        String url = Uri.parse("https://www.reddit.com/r/battlestations/hot.json")
                .buildUpon()
                .appendQueryParameter("after", after)
                .build()
                .toString();
        String jsonString = getUrlString(url);
        Log.i(TAG, "Received JSON: " + jsonString);
        JSONObject jsonBody = new JSONObject(jsonString);
        parseItems(items, jsonBody);
    return items;
}

回答1:

You are getting overlapping calls to FetchItemsTask due to how onScrollStateChanged works. If you swipe up and let things settle, here is how onScrollStateChanged is invoked:

onScrollStateChanged: SCROLL_STATE_DRAGGING
onScrollStateChanged: SCROLL_STATE_SETTLING
onScrollStateChanged: SCROLL_STATE_IDLE

This is what you would expect. If, however, you swipe up and then swipe up again before the view settles, this is what happens:

onScrollStateChanged: SCROLL_STATE_DRAGGING
onScrollStateChanged: SCROLL_STATE_SETTLING
onScrollStateChanged: SCROLL_STATE_DRAGGING
onScrollStateChanged: SCROLL_STATE_SETTLING
onScrollStateChanged: SCROLL_STATE_IDLE

This may seem surprising at first, but it makes sense if you think about it.

You are also not doing any checks for the newState in onScrollStateChanged.

If you are trying to implement an endless RecyclerView try searching for "endless recyclerview". There are many good resources on the web.