在使用Retrofit时滚动到RecyclerView底部时添加更多项目

时间:2017-12-11 14:37:55

标签: android android-recyclerview pagination retrofit recycler-adapter

我正在关注this教程实施分页,我正在密切关注它,但我不确定如何修改我当前的活动以实现OnLoadMoreListener。我正在使用改造中的ApiService来加载数据,这与生成随机字符串的教程不同。

这是我当前的RecyclerView适配器的样子:

public class CuratedSectionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private static int VIEW_TYPE_HEADER = 0;
    private static int VIEW_TYPE_ITEM = 1;
    private static int VIEW_TYPE_LOADING = 2;

    private int lastVisibleItem, totalItemCount;
    private int visibleThreshold = 2;
    private boolean isLoading;

    private List<Object> itemList;
    private OnLoadMoreListener onLoadMoreListener;

    public CuratedSectionAdapter(RecyclerView recyclerView, List<Object> itemList) {
        this.itemList = itemList;

        final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                totalItemCount = linearLayoutManager.getItemCount();
                lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
                if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                    if (onLoadMoreListener != null) {
                        onLoadMoreListener.onLoadMore();
                    }
                    isLoading = true;
                }
            }
        });
    }

    private class ItemViewHolder extends RecyclerView.ViewHolder {

        RecyclerView itemRecyclerView;
        CuratedSectionNestedAdapter nestedAdapter;
        LinearLayoutManager layoutManager;

        ItemViewHolder(View view) {
            super(view);
            itemRecyclerView = view.findViewById(R.id.recyclerView_nested);
            layoutManager = new LinearLayoutManager(view.getContext(), LinearLayoutManager.HORIZONTAL, false);
        }
    }

    private class HeaderViewHolder extends RecyclerView.ViewHolder {
        TextView textViewHeader;
        Typeface montserratMedium = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/Montserrat-Medium.ttf");

        HeaderViewHolder(View view) {
            super(view);
            textViewHeader = view.findViewById(R.id.textView_header);
            textViewHeader.setTypeface(montserratMedium);
        }
    }

    private class LoadingViewHolder extends RecyclerView.ViewHolder {
        public ProgressBar progressBar;

        public LoadingViewHolder(View view) {
            super(view);
            progressBar = (ProgressBar) view.findViewById(R.id.progress_bar);
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        if (holder.getItemViewType() == VIEW_TYPE_HEADER) {
            HeaderViewHolder viewHolder = (HeaderViewHolder) holder;
            CuratedSectionHeader header = (CuratedSectionHeader) itemList.get(position);

            viewHolder.textViewHeader.setText(header.getHeaderName());
        } else if (holder.getItemViewType() == VIEW_TYPE_ITEM) {
            ItemViewHolder viewHolder = (ItemViewHolder) holder;
            List<CuratedSectionItem> items = (List<CuratedSectionItem>) itemList.get(position);

            if (viewHolder.nestedAdapter != null) {
                viewHolder.nestedAdapter.setItems(items);
            } else {
                viewHolder.nestedAdapter = new CuratedSectionNestedAdapter(items);
                viewHolder.itemRecyclerView.setLayoutManager(viewHolder.layoutManager);
                viewHolder.itemRecyclerView.setAdapter(viewHolder.nestedAdapter);
            }
        } else if (holder.getItemViewType() == VIEW_TYPE_LOADING) {
            LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
            loadingViewHolder.progressBar.setIndeterminate(true);
        }

    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == VIEW_TYPE_HEADER) {
            return new HeaderViewHolder(LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.main_explore_header_row, parent, false));
        } else if (viewType == VIEW_TYPE_ITEM) {
            return new ItemViewHolder(LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.main_explore_row, parent, false));
        } else if (viewType == VIEW_TYPE_LOADING) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_loading, parent, false);
            return new LoadingViewHolder(view);
        }

        throw new RuntimeException("Adapter " + viewType + "not found");
    }

    @Override
    public int getItemCount() {
        return itemList.size();
    }

    @Override
    public int getItemViewType(int position) {

        if (itemList.get(position) instanceof  CuratedSectionHeader) {
            return VIEW_TYPE_HEADER;
        } else {
            return itemList.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
        }
    }

    public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
        this.onLoadMoreListener = mOnLoadMoreListener;
    }

    public void setLoaded() {
        isLoading = false;
    }
}

我的活动的当前架构使用私有类来进行API调用并加载数据。目前,所有商品都会立即加载,但理想情况下,一次只能加载2件商品。当我滚动到底部时,我不确定如何通过再次调用API服务来加载其他项目。至少,我确信我必须以某种方式使用curatedSectionAdapter.setOnLoadMoreListener

这就是我现在加载所有项目的方式:

private class Sections {
    List<CuratedSection> sections = new ArrayList<>();
    public Thread[] thread;

    private Sections() {}

    public void setSections(ArrayList<CuratedSection> sections) {
        this.sections = sections;
    }

    public void setSectionStories(String sectionId, List<CuratedSectionItem> stories) {
        for(CuratedSection s : sections){
            if(s.id != null && s.id.equals(sectionId)) {
                s.stories = stories;
            }
        }
    }

    public void loadStories(String sessionKey) {
        thread = new Thread[sections.size()];
        for( int s = 0; s < sections.size(); s++) {
            thread[s] = new Thread(new LoadStories(sessionKey, sections.get(s)));
            thread[s].start();
        }
        for( int f = 0; f < sections.size(); f++) {
            try {
                thread[f].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        recyclerView.setLayoutManager(layoutManager);
        curatedSectionAdapter = new CuratedSectionAdapter(recyclerView, this.getAdapterInfo());
        recyclerView.setAdapter(curatedSectionAdapter);
    }

    public void loadSections(int numSections) {
        swipeRefreshLayout.setRefreshing(false);
        LoadSections load = new LoadSections(numSections);
        load.run();
    }

    public List<Object> getAdapterInfo() {
        List<Object> list = new ArrayList<>();

        for (int i = 0; i < sections.size(); i++) {
            CuratedSection section = sections.get(i);
            CuratedSectionHeader header = new CuratedSectionHeader();
            header.setHeaderName(section.header);

            list.add(header);
            list.add(section.stories);
        }

        return list;
    }
}


private class LoadSections implements Runnable {

    int numSections;

    LoadSections(int numSections) {
        this.numSections = numSections;
    }

    @Override
    public void run() {
        SharedPreferences prefs = getSharedPreferences("user_session", MODE_PRIVATE);
        final String sessionKey = prefs.getString("session_key", null);

        Call<JsonArray> call;
        call = TravelersApi.endpoint().getCuratedSections(sessionKey);

        call.enqueue(new Callback<JsonArray>() {
            @Override
            public void onResponse(Call<JsonArray> call, Response<JsonArray> response) {
                if(response.code() != 200) {
                    Toast.makeText(getApplicationContext(), "Cannot load page as of the moment.", Toast.LENGTH_SHORT).show();
                    return;
                }
                JsonArray rawSections = response.body();
                if(rawSections.size() == 0) {
                    //TODO: show placeholder
                    return;
                }
                ArrayList<CuratedSection> sections = new ArrayList<>();
                for(int i = 0; i < numSections; i++) {
                    JsonObject jSection = rawSections.get(i).getAsJsonObject();
                    final CuratedSection section = new CuratedSection();
                    section.id = jSection.get("id").getAsString();
                    section.header = jSection.get("section_header").getAsString();
                    section.topicCount = jSection.get("topic_count").getAsInt();
                    section.isShown = jSection.get("is_shown").getAsBoolean();
                    section.stories = new ArrayList<>();

                    sections.add(section);
                }
                curated.setSections(sections);
                curated.loadStories(sessionKey);

                spinner.clearAnimation();
                spinner.setVisibility(View.GONE);
                header.setVisibility(View.VISIBLE);
                swipeRefreshLayout.setVisibility(View.VISIBLE);

            }

            @Override
            public void onFailure(Call<JsonArray> call, Throwable t) {
                Log.d("ERROR!", t.toString());
                t.printStackTrace();
            }
        });
    }
}

1 个答案:

答案 0 :(得分:2)

您可以通过直接将滚动侦听器设置为您的回收站视图来实现此目的。

recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            totalItemCount = linearLayoutManager.getItemCount();
            lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
            if (!isLoading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                // Call Load more method here to load next page data
               // Prevent multiple calls by using a boolean
                isLoading=true; // boolean to Prevent multiple calls
            }
        }
    });

OnLoadMoreListener 是您首先需要注册的界面。 对于分页,您的服务器应该处理分页计数。所以你还需要api来执行页面限制。