Infinitive RecyclerView not working for me

I know that this question has been asked many times before, but I am confused why sometimes the data is downloaded, and sometimes the data is not loaded after I get to the end of the list. Also, when I quickly scroll through the list and the new data has been downloaded, but immediately it returns me to the first item in the list and removes all new downloaded items from the next page from the server. So this is the second problem, and the third problem is that when I load items using SwipeRefreshLayout, I also do not get new items when I get to the end of the list.

I implemented this in my project: https://gist.github.com/ssinss/e06f12ef66c51252563e

list.setLayoutManager(manager); list.setEmptyView(emptyView); list.setItemAnimator(new DefaultItemAnimator()); list.setAdapter(mAdapter); loadJokes(1); list.addOnScrollListener(new EndlessRecyclerOnScrollListener(manager) { @Override public void onLoadMore(final int current_page) { loadMoreJokes(current_page); } }); 

Here is the way I download more items from the server:

 private void loadMoreJokes(int current_page) { StringRequest request = new StringRequest(Request.Method.GET, AppConfig.URL_GET_ALL_JOKES + current_page, new Response.Listener<String>() { @Override public void onResponse(String response) { hideDialog(); try { JSONObject object = new JSONObject(response); boolean error = object.getBoolean("error"); JSONArray jokes = object.getJSONArray("jokes"); if (!error) { for (int i = 0; i < jokes.length(); i++) { JSONObject object1 = jokes.getJSONObject(i); Joke joke = new Joke(); joke.setId(object1.optInt("id")); joke.setLikes(object1.optInt("likes")); joke.setComments(object1.optInt("comments")); joke.setJoke(object1.optString("joke")); joke.setCreatedAt(object1.optString("created_at")); joke.setName(object1.optString("user_name")); joke.setImagePath(object1.optString("image_path")); joke.setFacebookUserId(object1.optString("facebook_user_id")); joke.setCategory(object1.optString("category")); mJokes.add(joke); } menu.showMenu(true); } // Notify adapter that data has changed mAdapter.notifyDataSetChanged(); } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { hideDialog(); Toast.makeText(getActivity(), error.getMessage(), Toast.LENGTH_SHORT).show(); } }); AppController.getInstance().addToRequestQueue(request); } 

And here is the method when I load the first visible elements when someone starts the application:

 private void loadJokes(int page) { pDialog.setMessage("Loading.."); showDialog(); StringRequest request = new StringRequest(Request.Method.GET, AppConfig.URL_GET_ALL_JOKES + page, new Response.Listener<String>() { @Override public void onResponse(String response) { mJokes.clear(); hideDialog(); try { JSONObject object = new JSONObject(response); boolean error = object.getBoolean("error"); JSONArray jokes = object.getJSONArray("jokes"); if (!error) { for (int i = 0; i < jokes.length(); i++) { JSONObject object1 = jokes.getJSONObject(i); Joke joke = new Joke(); joke.setId(object1.optInt("id")); joke.setLikes(object1.optInt("likes")); joke.setComments(object1.optInt("comments")); joke.setJoke(object1.optString("joke")); joke.setCreatedAt(object1.optString("created_at")); joke.setName(object1.optString("user_name")); joke.setImagePath(object1.optString("image_path")); joke.setFacebookUserId(object1.optString("facebook_user_id")); joke.setCategory(object1.optString("category")); mJokes.add(joke); } menu.showMenu(true); } // Notify adapter that data has changed mAdapter.notifyDataSetChanged(); } catch (JSONException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { hideDialog(); menu.showMenu(true); Toast.makeText(getActivity(), error.getMessage(), Toast.LENGTH_SHORT).show(); } }); AppController.getInstance().addToRequestQueue(request); } 

And this is the onRefresh() method:

 @Override public void onRefresh() { new Handler().postDelayed(new Runnable() { @Override public void run() { refreshItems(); } }, 5000); } private void refreshItems() { loadJokes(1); mSwipeRefreshLayout.setRefreshing(false); } 

If I need to post more code, let me know. I really need to solve this problem as soon as I can. Therefore, the problems are as follows:

  • When you quickly scroll through the list, new items are loaded, but immediately after that it returns me to the beginning of the list, and when I go to the end of the list again, loading no longer responds.

  • After updating the list using SwipRefreshLayout also the scrolling does not respond at the end.

Note. Scrolling and loading new items only work if I am slowly navigating the list and if I have not scrolled the list of updates.

EDIT:

 @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_jokes, container, false); mContext = getActivity(); mView = (CoordinatorLayout) view.findViewById(R.id.coordinatorLayout); TextView tvEmptyText = (TextView) view.findViewById(R.id.tv_empty); ImageView ivSignal = (ImageView) view.findViewById(R.id.iv_signal); if (!ConnectionDetector.getInstance(getActivity()).isOnline() && mAdapter == null) { tvEmptyText.setVisibility(View.VISIBLE); ivSignal.setVisibility(View.VISIBLE); showNoInternetSnackbar(); } // INITIALIZE RECYCLER VIEW EmptyRecyclerView list = (EmptyRecyclerView) view.findViewById(R.id.list); mJokes = new ArrayList<>(); mAdapter = new RecyclerJokesAdapter(getActivity(), mJokes, JokesFragment.this, null); // Progress dialog pDialog = new ProgressDialog(getActivity()); pDialog.setMessage("Please wait"); pDialog.setIndeterminate(true); pDialog.setCancelable(false); showDialog(); View emptyView = inflater.inflate(R.layout.layout_empty_view, container, false); FloatingActionButton fab1 = (FloatingActionButton) view.findViewById(R.id.fab_funny); FloatingActionButton fab2 = (FloatingActionButton) view.findViewById(R.id.fab_good_morning); FloatingActionButton fab3 = (FloatingActionButton) view.findViewById(R.id.fab_good_night); FloatingActionButton fab4 = (FloatingActionButton) view.findViewById(R.id.fab_all); menu = (FloatingActionMenu) view.findViewById(R.id.menu_sort_jokes); fab1.setOnClickListener(this); fab2.setOnClickListener(this); fab3.setOnClickListener(this); fab4.setOnClickListener(this); mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_container); mSwipeRefreshLayout.setOnRefreshListener(this); mSwipeRefreshLayout.setColorSchemeResources( R.color.refresh_progress_1, R.color.refresh_progress_2, R.color.refresh_progress_3); LinearLayoutManager manager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false); list.setLayoutManager(manager); list.setEmptyView(emptyView); list.setItemAnimator(new DefaultItemAnimator()); list.setAdapter(mAdapter); if (ConnectionDetector.getInstance(mContext).isOnline()) { loadJokes(1); } else { showNoInternetSnackbar(); hideDialog(); } list.addOnScrollListener(new EndlessRecyclerOnScrollListener(manager) { @Override public void onLoadMore(final int current_page) { loadMoreJokes(current_page); } }); return view; } 
+5
source share
4 answers

The onCreate method initializes your adapter, recyclerView and List

 List<MyObject> myList = new ArrayList<>(); recyclerViewAdapter = new RecyclerViewAdapter(context, myList) myRecyclerView.setAdapter(recyclerViewAdapter); 

Now that you are loading data. add data to your myList and call notifyDataSetChange in your adpater

 myList.add(data); recyclerViewAdapter.notifyDataSetChange(); 
+1
source

Use this shell class

 import android.content.Context; import android.support.annotation.NonNull; import android.support.v7.widget.RecyclerView; import java.util.List; public abstract class RecyclerWrapperAdapter<E> extends RecyclerView.Adapter<RecyclerView.ViewHolder> { protected Context context; protected List<E> objects; public void setContext(Context context) { this.context = context; } public void setObjects(List<E> objects) { this.objects = objects; notifyDataSetChanged(); } public void add(@NonNull E object) { objects.add(object); notifyDataSetChanged(); } public void add(int position, @NonNull E object) { if (position < objects.size() && position >= 0) { objects.add(position, object); notifyItemChanged(position); notifyDataSetChanged(); } else if (position >= objects.size()) { objects.add(object); notifyDataSetChanged(); } } public void set(int position, @NonNull E object) { if (position < objects.size() && position >= 0) { objects.set(position, object); notifyItemChanged(position); } else if (position >= objects.size()) { objects.add(object); notifyDataSetChanged(); } } public void remove(@NonNull E object) { objects.remove(object); notifyDataSetChanged(); } public void remove(int position) { if (position >=0 && position < objects.size()) { objects.remove(position); notifyDataSetChanged(); } } public void removeAll() { objects.clear(); notifyDataSetChanged(); } public E getItem(int position) { return objects.get(position); } @Override public int getItemCount() { return objects.size(); } } 
0
source

Well, I did like this:

MainActivity.java

 public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener, onRecyclerViewListener { private RecyclerView mRecyclerView; private TextView tvEmptyView; private LinearLayoutManager mLayoutManager; private List<Object> studentList; protected Handler handler; private int count = 0; private SwipeRefreshLayout swipeRefreshLayout; private MyRecycleAdapter myRecycleAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); swipeRefreshLayout = (SwipeRefreshLayout)findViewById(R.id.swiperefresh); swipeRefreshLayout.setOnRefreshListener(this); swipeRefreshLayout.setColorSchemeResources(R.color.blue, R.color.purple, R.color.green, R.color.orange); tvEmptyView = (TextView) findViewById(R.id.empty_view); mRecyclerView = (RecyclerView)findViewById(R.id.recyclerView); studentList = new ArrayList<Object>(); handler = new Handler(); loadData(); mRecyclerView.setHasFixedSize(true); mLayoutManager = new LinearLayoutManager(this); mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); // use a linear layout manager mRecyclerView.setLayoutManager(mLayoutManager); myRecycleAdapter = new MyRecycleAdapter(mRecyclerView, studentList, R.layout.list_row, R.layout.progressbar_item, this); myRecycleAdapter.setLoadMoreEnable(true); myRecycleAdapter.setOnLoadMoreListener(new OnLoadMoreListener() { @Override public void onLoadMore() { count++; if (count == 4) { count = 0; myRecycleAdapter.setLoadMoreEnable(false); } else { myRecycleAdapter.setLoadMoreEnable(true); } //add null , so the adapter will check view_type and show progress bar at bottom studentList.add(null); myRecycleAdapter.notifyItemInserted(studentList.size() - 1); handler.postDelayed(new Runnable() { @Override public void run() { // remove progress item studentList.remove(studentList.size() - 1); myRecycleAdapter.notifyItemRemoved(studentList.size()); //add items one by one int start = studentList.size(); int end = start + 20; for (int i = start + 1; i <= end; i++) { studentList.add(new Student("Student " + i, "AndroidStudent" + i + "@gmail.com")); myRecycleAdapter.notifyItemInserted(studentList.size()); } myRecycleAdapter.setLoaded(); //or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged(); } }, 1000); } }); ItemViewHolderNew.setRecyclerListener(this); mRecyclerView.setAdapter(myRecycleAdapter); if (studentList.isEmpty()) { mRecyclerView.setVisibility(View.GONE); tvEmptyView.setVisibility(View.VISIBLE); } else { mRecyclerView.setVisibility(View.VISIBLE); tvEmptyView.setVisibility(View.GONE); } } private void loadData() { for (int i = 1; i <= 20; i++) { studentList.add(new Student("Student " + i, "androidstudent" + i + "@gmail.com")); } } @Override public void onRefresh() { swipeRefreshLayout.setRefreshing(true); new Handler().postDelayed(new Runnable() { @Override public void run() { swipeRefreshLayout.setRefreshing(false); } },5000); } @Override public void onBindView(View view, final ItemViewHolderNew itemViewHolder) { itemViewHolder.tvName = (TextView) view.findViewById(R.id.tvName); itemViewHolder.tvEmailId = (TextView) view.findViewById(R.id.tvEmailId); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, Object object, ItemViewHolderNew itemViewHolder) { Student studentObj = (Student)object; itemViewHolder.tvName.setText(studentObj.getName()); itemViewHolder.tvEmailId.setText(studentObj.getEmailId()); itemViewHolder.student= studentObj; } @Override public void setClickListener(View view, ItemViewHolderNew itemViewHolder) { Toast.makeText(view.getContext(), "OnClick :" + itemViewHolder.student.getName() + " \n " + itemViewHolder.student.getEmailId(), Toast.LENGTH_SHORT).show(); } public static class ItemViewHolderNew extends RecyclerView.ViewHolder{ public TextView tvName, tvEmailId; public Student student; private static onRecyclerViewListener mListener; public static void setRecyclerListener(onRecyclerViewListener listener){ mListener = listener; } public ItemViewHolderNew(View itemView) { super(itemView); mListener.onBindView(itemView, this); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { setClick(v); } }); } private void setClick(View v) { mListener.setClickListener(v, this); } } } 

Add OnLoadMoreListener.java Interface

 public interface OnLoadMoreListener { void onLoadMore(); } 

Add Student.java as a model class

 public class Student implements Serializable { private static final long serialVersionUID = 1L; private String name; private String emailId; public Student(String name, String emailId) { this.name = name; this.emailId = emailId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmailId() { return emailId; } public void setEmailId(String emailId) { this.emailId = emailId; } } 

activity_main.xml

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context=".MainActivity" tools:showIn="@layout/activity_main"> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swiperefresh" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="vertical"> </android.support.v7.widget.RecyclerView> </android.support.v4.widget.SwipeRefreshLayout> <TextView android:id="@+id/empty_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="No Records Here !" android:visibility="gone" /> </RelativeLayout> 

list_row.xml

 <?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <LinearLayout android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent" android:padding="5dp" android:background="?android:selectableItemBackground"> <TextView android:id="@+id/tvName" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:text="Name" android:textColor="@android:color/black" android:textSize="18sp" /> <TextView android:id="@+id/tvEmailId" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/tvName" android:layout_margin="5dp" android:text="Email Id" android:textColor="@android:color/black" android:textSize="12sp" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dp" android:text="Name" android:textColor="@android:color/black" android:textSize="18sp" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/tvName" android:layout_margin="5dp" android:text="Email Id" android:textColor="@android:color/black" android:textSize="12sp" /> </LinearLayout> </android.support.v7.widget.CardView> 

progressbar_item.xml

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:gravity="center" android:layout_width="match_parent" android:layout_height="match_parent"> <ProgressBar android:id="@+id/progressBar1" android:layout_width="wrap_content" android:layout_gravity="center_horizontal" android:layout_height="wrap_content" /> </LinearLayout> 

We work great with Endless, swipe the screen, download more RecyclerView.

Hope this helps you.

0
source

Volley RequestQueue uses a thread pool for network requests.

 /** Number of network request dispatcher threads to start. */ private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4; 

Obviously, when executing fast scrolling through the list several queries are generated in quick succession.

There is a chance that answers will be received asynchronously / from the sequence. It is also possible that the answers are β€œNo more data” / error responses, etc. Reach the answers with the next page of data, which may lead to unexpected behavior of your application.

mJokes how this mJokes your mJokes ArrayList member mJokes .

0
source

All Articles