【问题标题】:RecyclerView Endless Infinite Scrolling IssueRecyclerView 无限无限滚动问题
【发布时间】:2015-10-05 10:33:19
【问题描述】:

我正在尝试使用 RecyclerView 实现 Endless Infinite Scrolling,但我只获得前 10 条记录,没有获得接下来的 10 条记录,甚至在尝试滚动到底部时也没有任何进展。

而我本想在滚动时获得接下来的 10 条记录,依此类推...但只获得前 10 条记录

在这里我上传了我的 JSON 的 copy - 但我无法从同一个 url 获取数据,这就是我使用客户端的 url 和本地主机的原因。

我在关注this教程

这是我的完整代码,我可以知道我在哪里做错了吗?

JSON:

{
  "names": [
    {
      "name": "Name 1"
    },
    {
      "name": "Name 2"
    },
    ....
    {
      "name": "Name 60"
    }
  ]
}

日志:

D/name -(13759): Name 1
D/name -(13759): Name 2
.......................
D/name -(13759): Name 60

这是我用来解析 JSON 数据的更新代码

MainActivity.java:已更新

public class MainActivity extends AppCompatActivity {

private Toolbar toolbar;

private TextView tvEmptyView;
private RecyclerView mRecyclerView;
private DataAdapter mAdapter;
private LinearLayoutManager mLayoutManager;

private ArrayList<Student> studentList;

protected Handler handler;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    toolbar = (Toolbar) findViewById(R.id.toolbar);
    tvEmptyView = (TextView) findViewById(R.id.empty_view);
    mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

    studentList = new ArrayList<Student>();

    handler = new Handler();
    if (toolbar != null) {
        setSupportActionBar(toolbar);
        getSupportActionBar().setTitle("Android Students");
    }

    loadData();

}

// load initial data
private void loadData() {       
    new Parser().execute("http://10.0.2.2/jsons/mytest.txt");               
}

class Parser extends AsyncTask<String, Void, Boolean> {

    ProgressDialog dialog;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        dialog = new ProgressDialog(MainActivity.this);
        dialog.show();
        dialog.setCancelable(false);
    }

    @Override
    protected Boolean doInBackground(String... urls) {
        try {
            //------------------>>
            HttpGet httppost = new HttpGet(urls[0]);
            HttpClient httpclient = new DefaultHttpClient();
            HttpResponse response = httpclient.execute(httppost);

            // StatusLine stat = response.getStatusLine();
            int status = response.getStatusLine().getStatusCode();

            if (status == 200) {
                HttpEntity entity = response.getEntity();
                String data = EntityUtils.toString(entity);

                JSONObject jsono = new JSONObject(data);
                JSONArray jarray = jsono.getJSONArray("names");

                for (int i = 0; i < jarray.length(); i++) {
                    JSONObject object = jarray.getJSONObject(i);

                    Student actor = new Student();

                    actor.setName(object.getString("name"));
                    Log.d("name - ", object.getString("name"));

                    studentList.add(actor);             
                }

                Log.d("MainActivity:StudentList ", "The size "+studentList.size());                 

                return true;
            }

            //------------------>>

        } catch (ParseException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return false;

    }

    protected void onPostExecute(Boolean result) {
        dialog.cancel();

        Log.d("MainActivity:StudentList ", "The size "+studentList.size());

        ArrayList< Student > temArray = 
                 new ArrayList< Student >(studentList.subList(0, 10));           
        mAdapter = new DataAdapter(temArray, mRecyclerView);

        Log.d("MainActivity:TempList ", "The size "+temArray.size());

        // set the adapter object to the Recyclerview
        mRecyclerView.setAdapter(mAdapter);     
        // use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        mRecyclerView.setHasFixedSize(true);

        mLayoutManager = new LinearLayoutManager(MainActivity.this);

        // use a linear layout manager
        mRecyclerView.setLayoutManager(mLayoutManager);

        if (studentList.isEmpty()) {
            mRecyclerView.setVisibility(View.GONE);
            tvEmptyView.setVisibility(View.VISIBLE);
        } else {
            mRecyclerView.setVisibility(View.VISIBLE);
            tvEmptyView.setVisibility(View.GONE);
        }

        mAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
            @Override
            public void onLoadMore() {
                //add null , so the adapter will check view_type and show progress bar at bottom
                studentList.add(null);
                mAdapter.notifyItemInserted(studentList.size() - 1);

                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //   remove progress item
                        studentList.remove(studentList.size() - 1);
                        mAdapter.notifyItemRemoved(studentList.size());
                        //add items one by one
                        int start = studentList.size();
                        int end = start + 10;

                        for (int i = start + 1; i < end; i++) {
                            mAdapter.notifyItemInserted(studentList.size());
                        }
                        mAdapter.setLoaded();
                       //or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged();
                    }
                }, 2000);
            }
        });
    }
}

}

DataAdapter.java:

public class DataAdapter extends RecyclerView.Adapter {
    private final int VIEW_ITEM = 1;
    private final int VIEW_PROG = 0;

    private List<Student> studentList;

    // The minimum amount of items to have below your current scroll position
    // before loading more.
    private int visibleThreshold = 5;
    private int lastVisibleItem, totalItemCount;
    private boolean loading;
    private OnLoadMoreListener onLoadMoreListener;

    public DataAdapter(List<Student> students, RecyclerView recyclerView) {
        studentList = students;

        if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {

            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 (!loading
                                    && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                                // End has been reached
                                // Do something
                                if (onLoadMoreListener != null) {
                                    onLoadMoreListener.onLoadMore();
                                }
                                loading = true;
                            }
                        }
                    });
        }
    }

    @Override
    public int getItemViewType(int position) {
        return studentList.get(position) != null ? VIEW_ITEM : VIEW_PROG;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
            int viewType) {
        RecyclerView.ViewHolder vh;
        if (viewType == VIEW_ITEM) {
            View v = LayoutInflater.from(parent.getContext()).inflate(
                    R.layout.list_row, parent, false);

            vh = new StudentViewHolder(v);
        } else {
            View v = LayoutInflater.from(parent.getContext()).inflate(
                    R.layout.progress_item, parent, false);

            vh = new ProgressViewHolder(v);
        }
        return vh;
    }

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

            Student singleStudent= (Student) studentList.get(position);

            ((StudentViewHolder) holder).tvName.setText(singleStudent.getName());

            ((StudentViewHolder) holder).student= singleStudent;

        } else {
            ((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
        }
    }

    public void setLoaded() {
        loading = false;
    }

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

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


    //
    public static class StudentViewHolder extends RecyclerView.ViewHolder {
        public TextView tvName;     

        public Student student;

        public StudentViewHolder(View v) {
            super(v);
            tvName = (TextView) v.findViewById(R.id.tvName);

            v.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Toast.makeText(v.getContext(),
                            "OnClick :" + student.getName(),
                            Toast.LENGTH_SHORT).show();

                }
            });
        }
    }

    public static class ProgressViewHolder extends RecyclerView.ViewHolder {
        public ProgressBar progressBar;

        public ProgressViewHolder(View v) {
            super(v);
            progressBar = (ProgressBar) v.findViewById(R.id.progressBar1);
        }
    }
}

OnLoadMoreListener.java:

public interface OnLoadMoreListener {
     void onLoadMore();
}

【问题讨论】:

  • 你能在浏览器中执行10.0.2.2/jsons/mytest.txt 看看你得到了什么吗?
  • 你能把data 登录到LogCat 看看打印什么吗?
  • 你没有在 loadMore 的循环中添加项目
  • 因为您一次加载所有项目,我认为您不需要加载更多。您尚未更改执行后列表视图的可见性。在异步任务的执行后添加if (studentList.isEmpty()) { mRecyclerView.setVisibility(View.GONE); tvEmptyView.setVisibility(View.VISIBLE); } else { mRecyclerView.setVisibility(View.VISIBLE); tvEmptyView.setVisibility(View.GONE); }

标签: android json android-recyclerview infinite-scroll endlessscroll


【解决方案1】:

使用此代码解决后,我遇到了同样的问题... 首先..创建这个类

public abstract class EndlessOnScrollListener extends OnScrollListener {

    public static String TAG = EndlessOnScrollListener.class.getSimpleName();

    // use your LayoutManager instead
    private LinearLayoutManager llm;

    public EndlessOnScrollListener(LinearLayoutManager sglm) {
        this.lm = llm;
    }

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

        if (!recyclerView.canScrollVertically(1)) {
            onScrolledToEnd();
        }
    }

    public abstract void onScrolledToEnd();
}

第二个..在你的活动中使用这个

recyclerView.addOnScrollListener(new EndlessOnScrollListener() {

    @Override
    public void onScrolledToEnd() {
        if (!loading) {
            loading = true;
            // add 10 by 10 to tempList then notify changing in data
        }
        loading = false;
    }
});

这对我有用....我希望它对你有用。

【讨论】:

    【解决方案2】:

    试试 notifyItemRangeChanged

    yourCurrentList.addAll(newData);    
    mAdapter.notifyItemRangeChanged(yourCurretList.size() + 1, newDataSize);
    

    我想这会对你有所帮助。

    【讨论】:

      【解决方案3】:

      替换

      private List<Student> studentList;
      

      private List<Object> list;
      

      也替换

      @Override
      public int getItemViewType(int position) {
          return studentList.get(position) != null ? VIEW_ITEM : VIEW_PROG;
      }
      

      @Override
      public int getItemViewType(int position) {
        return list.get(position) instanceof Student ?  VIEW_ITEM : VIEW_PROG;
      }
      

      用于检测您可以使用的列表结尾

      @Override
      public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                  super.onScrollStateChanged(recyclerView, newState);
      
                  // When went to the end of the list, load more posts
                  if (newState == RecyclerView.SCROLL_STATE_IDLE) {
      
                      if (linearLayoutManager.findLastVisibleItemPosition() >= linearLayoutManager.getItemCount() - 1) {
      
                          // Grow List
                      }
                  }
      }
      

      也用于添加加载项。在适配器中添加此代码

      public void addLoadingView(){
         list.add(new Object());
         notifyDataSetChanged();
      }
      

      【讨论】:

        【解决方案4】:

        1.

        将前 11 个 recyclerview 项目设为空白(并显示进度条 连续),见下面的截图:

        loadData方法改成:

        private void loadData() {
          new Parser().execute("http://clienturl.com/jsons/mytest.txt");  
         }
        

        2.

        而我想获得前 10 条记录,然后滚动下 10 条 记录等等……

        ParseronPostExecute方法改成:

        protected void onPostExecute(Boolean result) {
            dialog.cancel();
            ArrayList< Student > temArray = 
                         new ArrayList< Student >(studentList.subList(0, 10));           
            mAdapter = new DataAdapter(temArray, mRecyclerView);
        
            // set the adapter object to the Recyclerview
            mRecyclerView.setAdapter(mAdapter);
         }
        

        并且还从onCreate 方法中删除以下行:

            mAdapter = new DataAdapter(studentList, mRecyclerView);
        
            // set the adapter object to the Recyclerview
            mRecyclerView.setAdapter(mAdapter);
        

        【讨论】:

        • @Oreo: ok 在mRecyclerView.setAdapter(mAdapter); 行之后将mAdapter.setOnLoadMoreListener 方法代码移到onPostExecute 内
        • @Oreo:已解决或仍面临同样的问题?
        • @Oreo:在studentList 中获取数据?使用日志并检查studentListtemArray ArrayList Size
        • @Oreo:请在onPostExecute方法中添加调试器并检查它是否正在执行?
        【解决方案5】:

        尝试改变

        int i = start + 1; i <= end; i++
        

        在for循环中

        int i = start + 1; i < end; i++
        

        &lt;= 验证添加了一个额外的项目。

        【讨论】:

        • 我本想在滚动条上获取接下来的 10 条记录,依此类推...但只获取前 10 条记录,请查看我上面的更新代码
        【解决方案6】:

        问题 1:在为 RecyclerView 设置 LayoutManager 之前,您已经创建了 mAdapter 的新实例。从而DataAdapter中添加ScrollListener的构造函数代码不会被执行,因为recyclerView.getLayoutManager()返回null

            if (recyclerView.getLayoutManager() instanceof LinearLayoutManager){
                // code to add ScrollListener is never executed
            }
        

        修复:首先为 Recyclerview 设置LayoutManager,然后创建如下所示的适配器:

            // use a linear layout manager
            mRecyclerView.setLayoutManager(mLayoutManager);
            mAdapter = new DataAdapter(temArray, mRecyclerView);
            // set the adapter object to the Recyclerview
            mRecyclerView.setAdapter(mAdapter);
        

        问题 2: 您已使用 temArray 创建 DataAdapter 但在 onLoadMore() 您使用 studentList 添加/删除新项目,因为 studentList 不是与mAdapter 绑定,您的更改不会反映在 UI 中。

        修复:temArray 声明为类级别变量并使用temArray 来操作项目。

         //class variable
         private ArrayList<Student> temArray = new ArrayList<Student>();
        
         handler.postDelayed(new Runnable() {
                    @Override public void run() {
                      //   remove progress item
                      temArray.remove(temArray.size() - 1);
                      mAdapter.notifyItemRemoved(temArray.size());
                      //add items one by one
                      int start = temArray.size();
                      int end = start + 10;
                      if(end<=studentList.size()){
                        temArray.addAll(studentList.subList(start,end));
                      }   
                      mAdapter.setLoaded();
                    }
                  }, 2000);
        

        【讨论】:

          【解决方案7】:
          for (int i = start + 1; i < end; i++) {
              studentList.add(add data here) ;
              mAdapter.notifyItemInserted(studentList.size());
          }
          

          【讨论】:

          • 我认为您必须在 notifyItemInserted 之前将数据添加到列表中。
          【解决方案8】:
                  mAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
                              @Override
                              public void onLoadMore() {
                                  //add null , so the adapter will check view_type and show progress bar at bottom
                                  studentList.add(null);
                                  mAdapter.notifyItemInserted(studentList.size() - 1);
          
                                  handler.postDelayed(new Runnable() {
                                      @Override
                                      public void run() {
                                          //   remove progress item
                                          studentList.remove(studentList.size() - 1);
                                          mAdapter.notifyItemRemoved(studentList.size());
                                          //add items one by one
                                          int start = studentList.size();
                                          int end = start + 10;
          
                                          for (int i = start + 1; i < end; i++) {
             // studentList.add();
                                              mAdapter.notifyItemInserted(studentList.size());
                                          }
                                          mAdapter.setLoaded();
                                         //or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged();
                                      }
                                  }, 2000);
                              }
                          });
          

          好的,所以您插入了进度条,然后您也将其删除了,但您从未插入下一个要显示的学生... 类似 studentList.add();

          希望能解决你的问题...祝你好运..

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-01-30
            • 1970-01-01
            • 1970-01-01
            • 2018-05-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多