如何使用 JSON API 在滚动时在 recyclerview 中加载更多数据

Posted

技术标签:

【中文标题】如何使用 JSON API 在滚动时在 recyclerview 中加载更多数据【英文标题】:How to load more data in recyclerview on scroll using JSON API 【发布时间】:2021-08-29 04:55:37 【问题描述】:

我正在滚动的 recyclerview 中实现分页。我正在从 JSON API 获取数据。下面是片段类的代码。第一页在 recyclerview 中成功加载,但是当我滚动到底部时,第二页没有加载并引发以下错误:

java.lang.IndexOutOfBoundsException:索引:10,大小:10

这是我的片段类:

public class LeadsFragment extends Fragment 

    RecyclerView recyclerView;
    LeadsAdapter leadsAdapter;
    List<LeadModel> rowsArrayList = new ArrayList<>();
    private LinearLayoutManager layoutManager;
    Toolbar toolbar;
    private int page = 1;
    private int totalItemCount;
    private int firstVisibleItem;
    private int visibleItemCount;
    private int previousTotal;
    private boolean isLoad=true;
    String url;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) 

        View view = inflater.inflate(R.layout.fragment_leads, container, false);

        toolbar = view.findViewById(R.id.toolbar);
        ( (AppCompatActivity) getActivity() ).setSupportActionBar(toolbar);
        ( (AppCompatActivity) getActivity() ).getSupportActionBar().setTitle("");

        url = "myurl?page="+page;
        recyclerView = view.findViewById(R.id.recyclerview);
        recyclerView.setHasFixedSize(true);
        layoutManager = new LinearLayoutManager(getActivity());
        recyclerView.setLayoutManager(layoutManager);
        leadsAdapter = new LeadsAdapter(getContext(), rowsArrayList, recyclerView);
        recyclerView.setAdapter(leadsAdapter);

        getAPIData();
        pagination();

        return view;

    

    private void getAPIData() 

        StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() 
            @Override
            public void onResponse(String response) 

                GsonBuilder gsonBuilder = new GsonBuilder();
                Gson gson = gsonBuilder.create();

                LeadModel leadModelList = gson.fromJson(response, LeadModel.class);

                for (int i = 0; i < leadModelList.getData().size(); i++) 
                    rowsArrayList.add(leadModelList);
                
leadsAdapter.setItems(rowsArrayList);
                leadsAdapter.notifyDataSetChanged();
            
        , new Response.ErrorListener() 
            @Override
            public void onErrorResponse(VolleyError error) 

                Toast.makeText(getContext(), error.toString(), Toast.LENGTH_SHORT).show();

            
        );

        RequestQueue queue = Volley.newRequestQueue(getContext());
        queue.add(stringRequest);
    

    private void pagination() 

        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() 
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) 
                super.onScrollStateChanged(recyclerView, newState);
            

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) 
                super.onScrolled(recyclerView, dx, dy);

                if (dy > 0) 
                    visibleItemCount = layoutManager.getChildCount();
                    totalItemCount = layoutManager.getItemCount();
                    firstVisibleItem = layoutManager.findFirstVisibleItemPosition();

                    Log.e("visibleItemCount", "." + visibleItemCount);
                    Log.e("totalItemCount", "." + totalItemCount);
                    Log.e("firstVisibleItem", "." + firstVisibleItem);

                    if (isLoad) 
                        if (totalItemCount > previousTotal) 
                            previousTotal = totalItemCount;
                            page++;
                            isLoad = false;
                            Log.e("previousTotal", "." + previousTotal);
                            Log.e("Pageeeee", "." + page);

                        
                    
                    if (!isLoad && ( firstVisibleItem + visibleItemCount ) >= totalItemCount) 
                        Log.e("Checking", "." + page);
                        getAPIData();
                        isLoad = true;
                    
                
            
        );

    

我的适配器类:

public class LeadsAdapter extends RecyclerView.Adapter<LeadsAdapter.ViewHolder> 

    Context context;
    List<LeadModel> leadsModelList;
    LeadsMeta leadsMetaList;

    RecyclerView recyclerView;
    final View.OnClickListener onClickListener = new MyOnClickListener();

    public LeadsAdapter(Context context, List<LeadModel> leadsModelList, RecyclerView recyclerView) 
        this.context = context;
        this.leadsModelList = leadsModelList;
        this.recyclerView = recyclerView;
    

    public void setItems(List<LeadModel> leadsModelList) 
        this.leadsModelList= new ArrayList<>(leadsModelList);
    

    public static class ViewHolder extends RecyclerView.ViewHolder 
        TextView name, topic, sub_topic, city, credits, quotes;

        public ViewHolder(@NonNull View itemView) 
            super(itemView);

            name = itemView.findViewById(R.id.tvName);
            topic = itemView.findViewById(R.id.tvTopic);
            sub_topic = itemView.findViewById(R.id.tvSubTopic);
            city = itemView.findViewById(R.id.tvLocation);
            credits = itemView.findViewById(R.id.tvCredits);
            quotes = itemView.findViewById(R.id.tvQuotes);
        
    


    @NonNull
    @Override
    public LeadsAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) 

        LayoutInflater inflater = LayoutInflater.from(context);
        View view = inflater.inflate(R.layout.lead_card, viewGroup, false);
        view.setOnClickListener(onClickListener);
        LeadsAdapter.ViewHolder viewHolder = new LeadsAdapter.ViewHolder(view);
        return viewHolder;
    

    @Override
    public void onBindViewHolder(@NonNull LeadsAdapter.ViewHolder viewHolder, int position) 

        LeadModel leadsModel = leadsModelList.get(position);

        viewHolder.name.setText(leadsModel.getData().get(position).getName());
    

    @Override
    public int getItemCount() 
        return leadsModelList.size();

    

【问题讨论】:

【参考方案1】:

每当调用 getApi 方法发送新响应并将数据再次添加到列表时,但该列表未发送到适配器以更新新列表。 而不是这样 leadsAdapter = new LeadsAdapter(getContext(), rowsArrayList, recyclerView); 在adapter中创建一个以list为参数的方法,并将arraylist传递给方法,并在有新数据响应时通知。

【讨论】:

我正在调用leadsAdapter.notifyDataSetChanged(); 请再次阅读我的回答。您必须再次将数组列表发送到适配器。 你能再解释一下吗 不是在适配器构造函数中发送arraylist,而是在适配器中创建一个公共方法并在notifydatasetchanged之前传递arraylist。 参考这个***.com/questions/35147466/…

以上是关于如何使用 JSON API 在滚动时在 recyclerview 中加载更多数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在远程访问其 JSON API 时在 Jenkins 中进行身份验证?

如何使用 JSON API 在 recyclerview 滚动上加载更多数据

如何制作滚动视图,滚动iOS时在特定页面中滚动

在 400 HTTP 响应时在警报视图上显示 API 响应 JSON 格式的错误结果

全屏 UICollectionView:如何在滚动时在全屏单元格(或部分)之间添加间距

如何在运行时在垂直可滚动页面内动态创建水平可滚动 Gridview