web-dev-qa-db-fra.com

Problème de défilement infini sans fin de RecyclerView

J'essaie d'implémenter Endless Infinite Scrolling avec RecyclerView, mais je n'obtiens que les 10 premiers enregistrements, pas les 10 prochains enregistrements et même aucun progrès en essayant de faire défiler en bas.

Alors que je devais obtenir les 10 enregistrements suivants sur le défilement et ainsi de suite ... Mais obtenir uniquement les 10 premiers enregistrements

Ici, j'ai téléchargé copie de mon JSON - Mais je ne peux pas récupérer les données de la même URL, c'est pourquoi j'utilise l'URL du client et l'hôte local.

Je suis this tutorial

Voici mon code complet, puis-je savoir où je fais une erreur?

JSON:

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

Journal:

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

Voici mon code mis à jour, que j'utilise pour analyser les données JSON

MainActivity.Java: MISE À JOUR

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();
}
21
Oreo

J'ai eu le même problème une fois que je l'ai résolu en utilisant ce code ... Tout d'abord .. créez cette classe

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();
}

Deuxième .. dans votre activité, utilisez ceci

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;
    }
});

Cela fonctionne pour moi .... J'espère que cela fonctionne pour vous.

3
ahmed ghanayem

Essayez notifyItemRangeChanged

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

Je pense que cela vous aidera.

1
savepopulation

Essayez de changer le

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

dans la boucle for

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

Le <= la validation ajoute un élément supplémentaire.

0
Osvaldo Bringaz

1.

Obtenir les 11 premiers éléments de la vue de recyclage vides (et afficher la barre de progression en continu), voir la capture d'écran ci-dessous:

Modifiez la méthode loadData comme suit:

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

2.

Alors que je devais obtenir les 10 premiers enregistrements, et faire défiler les 10 enregistrements suivants et ainsi de suite ...

Modifiez la méthode onPostExecute de Parser comme suit:

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);
 }

Et supprimez également les lignes suivantes de la méthode onCreate:

    mAdapter = new DataAdapter(studentList, mRecyclerView);

    // set the adapter object to the Recyclerview
    mRecyclerView.setAdapter(mAdapter);
0
ρяσѕρєя K

Issue-1: Vous avez créé une nouvelle instance de mAdapter avant de définir le LayoutManager pour RecyclerView. Ainsi, le code constructeur dans le DataAdapter à ajouter ScrollListener n'est pas exécuté puisque recyclerView.getLayoutManager() renvoie null:

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

Fix: Définissez d'abord le LayoutManager pour le Recyclerview puis créez l'adaptateur comme ci-dessous:

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

Issue-2: Vous avez utilisé temArray pour créer DataAdapter mais dans onLoadMore() vous utilisez le studentList pour ajouter/supprimez les nouveaux éléments, puisque studentList n'est pas lié à mAdapter vos modifications ne sont pas reflétées dans l'interface utilisateur.

Fix: Déclarez temArray comme variable au niveau de la classe et utilisez temArray pour manipuler les éléments.

 //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);
0
blizzard

remplacer

private List<Student> studentList;

avec

private List<Object> list;

remplacer également

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

avec

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

pour détecter la fin de la liste, vous pouvez utiliser

@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
                }
            }
}

Aussi pour ajouter un élément de chargement. ajouter ce code dans l'adaptateur

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