SetOnScrollListener in RecyclerView [duplicate] - android

How Do I show progress bar at bottom when user reached to items those are visible in a list.
I have written a code in which i am getting data using web service, now i would like to populate partial records, because i have around 630 records in my JSON.
Here is my whole code which i am using to get data from JSON and to populate into RecyclerView.
Here is how my JSON looks, but real JSON contains over 600 records:
http://walldroidhd.com/api.php
Can someone guide me where i have to make changes in my code ?
I want to populate more records whenever user do scroll to bottom using progressbar, still i am showing all the records.
RecyclerViewFragment.java:
public class RecyclerViewFragment extends Fragment {
RecyclerView mRecyclerView;
LinearLayoutManager mLayoutManager;
RecyclerView.Adapter mAdapter;
ArrayList<NatureItem> actorsList;
private int previousTotal = 0;
private boolean loading = true;
private int visibleThreshold = 5;
int firstVisibleItem, visibleItemCount, totalItemCount;
public static RecyclerViewFragment newInstance() {
return new RecyclerViewFragment();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_recyclerview_advance, container, false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
actorsList = new ArrayList<NatureItem>();
new JSONAsyncTask().execute("my JSON url");
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new GridLayoutManager(getActivity(), 2);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = mRecyclerView.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
// End has been reached
Log.i("...", "end called");
// Do something
loading = true;
}
}
});
// mAdapter = new CardAdapter();
mAdapter = new RecyclerViewMaterialAdapter(new CardAdapter(getActivity(), actorsList), 2);
mRecyclerView.setAdapter(mAdapter);
MaterialViewPagerHelper.registerRecyclerView(getActivity(), mRecyclerView, null);
mRecyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
Toast.makeText(getActivity(), String.valueOf(position), Toast.LENGTH_LONG).show();
}
})
);
}
class JSONAsyncTask extends AsyncTask<String, Void, Boolean> {
ProgressDialog dialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(getActivity());
dialog.setMessage("Loading, please wait");
dialog.setTitle("Connecting server");
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 = null;
try {
data = EntityUtils.toString(entity);
} catch (IOException e) {
e.printStackTrace();
}
JSONObject jsono = null;
try {
jsono = new JSONObject(data);
} catch (JSONException e) {
e.printStackTrace();
}
JSONArray jarray = jsono.getJSONArray("wallpapers");
for (int i = 0; i < jarray.length(); i++) {
JSONObject object = jarray.getJSONObject(i);
NatureItem actor = new NatureItem();
actor.setName(object.getString("id"));
actor.setThumbnail(object.getString("thumb_url"));
actorsList.add(actor);
}
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();
mAdapter.notifyDataSetChanged();
if (result == false) {
Toast.makeText(getActivity(), "Unable to fetch data from server", Toast.LENGTH_LONG).show();
}
else {
}
}
}
}
CardAdapter.java:
public class CardAdapter extends RecyclerView.Adapter<CardAdapter.ViewHolder> {
private ArrayList<NatureItem> mItems;
private Context mContext;
public CardAdapter(Context context, ArrayList<NatureItem> feedItemList) {
this.mItems = feedItemList;
this.mContext = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.recycler_view_card_item, viewGroup, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
NatureItem nature = mItems.get(i);
viewHolder.tvNature.setText(nature.getName());
Picasso.with(mContext).load(nature.getThumbnail())
.error(R.mipmap.ic_launcher)
.placeholder(R.mipmap.ic_launcher)
.into(viewHolder.imgThumbnail);
}
#Override
public int getItemCount() {
return mItems.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
public ImageView imgThumbnail;
public TextView tvNature;
public ViewHolder(View itemView) {
super(itemView);
imgThumbnail = (ImageView)itemView.findViewById(R.id.img_thumbnail);
tvNature = (TextView)itemView.findViewById(R.id.tv_nature);
}
}
}
Here is how i have implemented Endless as well, using this:
mRecyclerView.setOnScrollListener(new EndlessRecyclerOnScrollListener(linearLayoutManager) {
#Override
public void onLoadMore(int current_page) {
// do something...
}
});
Note: I would personally prefer RecyclerView onScroll functionality to get my work done.

Activity Class with recylcerview in xml layout file
public class WallpaperActivity extends AppCompatActivity implements OnTaskCompleted {
private static final String TAG = "WallpaperActivity";
private Toolbar toolbar;
private RecyclerView mRecyclerView;
private WallPaperDataAdapter mAdapter;
private LinearLayoutManager mLayoutManager;
// to keep track which pages loaded and next pages to load
public static int pageNumber;
private List<WallPaper> wallpaperImagesList;
protected Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.wallpaper_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
pageNumber = 1;
wallpaperImagesList = new ArrayList<WallPaper>();
handler = new Handler();
if (toolbar != null) {
setSupportActionBar(toolbar);
getSupportActionBar().setTitle("WallPapers");
}
// 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(this);
// use a linear layout manager
mRecyclerView.setLayoutManager(mLayoutManager);
// create an Object for Adapter
mAdapter = new WallPaperDataAdapter(wallpaperImagesList, mRecyclerView);
// set the adapter object to the Recyclerview
mRecyclerView.setAdapter(mAdapter);
getWebServiceData();
mAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
//add null , so the adapter will check view_type and show progress bar at bottom
wallpaperImagesList.add(null);
mAdapter.notifyItemInserted(wallpaperImagesList.size() - 1);
++pageNumber;
getWebServiceData();
}
});
}
public void getWebServiceData() {
BackGroundTask backGroundTask = new BackGroundTask(this, this, pageNumber);
backGroundTask.execute();
}
#Override
public void onTaskCompleted(String response) {
parsejosnData(response);
}
public void parsejosnData(String response) {
try {
JSONObject jsonObject = new JSONObject(response);
// String json = jsonObject.toString();
JSONArray jsonArray = jsonObject.getJSONArray("wallpapers");
if (jsonArray != null) {
// looping through All albums
if (pageNumber > 1) {
wallpaperImagesList.remove(wallpaperImagesList.size() - 1);
mAdapter.notifyItemRemoved(wallpaperImagesList.size());
}
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject c = jsonArray.getJSONObject(i);
// Storing each json item values in variable
String id = c.getString("id");
String orig_url = c.getString("orig_url");
String thumb_url = c.getString("thumb_url");
String downloads = c.getString("downloads");
String fav = c.getString("fav");
// Creating object for each product
WallPaper singleWall = new WallPaper(id, orig_url, thumb_url, downloads, fav);
// adding HashList to ArrayList
wallpaperImagesList.add(singleWall);
handler.post(new Runnable() {
#Override
public void run() {
mAdapter.notifyItemInserted(wallpaperImagesList.size());
}
});
}
mAdapter.setLoaded();
} else {
Log.d("Wallpapers: ", "null");
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
Adapter Class
public class WallPaperDataAdapter extends RecyclerView.Adapter {
private final int VIEW_ITEM = 1;
private final int VIEW_PROG = 0;
private List<WallPaper> imagesList;
// 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 WallPaperDataAdapter(List<WallPaper> imagesList1, RecyclerView recyclerView) {
imagesList = imagesList1;
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 imagesList.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.wallpaper_row, parent, false);
vh = new WallPaperViewHolder(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 WallPaperViewHolder) {
WallPaper singleWallPaper = (WallPaper) imagesList.get(position);
Glide.with(((WallPaperViewHolder) holder).thumbIcon.getContext())
.load(singleWallPaper.getThumbUrl())
.centerCrop()
.placeholder(R.drawable.bg)
.crossFade()
.into(((WallPaperViewHolder) holder).thumbIcon);
} else {
((ProgressViewHolder) holder).progressBar.setIndeterminate(true);
}
}
public void setLoaded() {
loading = false;
}
#Override
public int getItemCount() {
return imagesList.size();
}
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
this.onLoadMoreListener = onLoadMoreListener;
}
//
public static class WallPaperViewHolder extends RecyclerView.ViewHolder {
public ImageView thumbIcon;
public WallPaperViewHolder(View v) {
super(v);
thumbIcon = (ImageView) v.findViewById(R.id.thumbIcon);
}
}
public static class ProgressViewHolder extends RecyclerView.ViewHolder {
public ProgressBar progressBar;
public ProgressViewHolder(View v) {
super(v);
progressBar = (ProgressBar) v.findViewById(R.id.progressBar1);
}
}
}
wallpaper_row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/thumbIcon"
android:layout_width="160dp"
android:layout_height="160dp"
android:layout_centerInParent="true"
android:layout_margin="2dp"
android:gravity="center" />
</RelativeLayout>
progress_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ProgressBar
android:id="#+id/progressBar1"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:layout_height="wrap_content" />
</LinearLayout>
Separate BackGroundTask.java
public class BackGroundTask extends AsyncTask<Object, Void, String> {
private ProgressDialog pDialog;
public OnTaskCompleted listener = null;//Call back interface
Context context;
int pageNumber;
public BackGroundTask(Context context1, OnTaskCompleted listener1, int pageNumber) {
context = context1;
listener = listener1; //Assigning call back interface through constructor
this.pageNumber = pageNumber;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(Object... params) {
//My Background tasks are written here
synchronized (this) {
String url = Const.URL_WALLPAPERS_HD + pageNumber;
String jsonStr = ServiceHandler.makeServiceCall(url, ServiceHandler.GET);
Log.i("Url: ", "> " + url);
Log.i("Response: ", "> " + jsonStr);
return jsonStr;
}
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
listener.onTaskCompleted(result);
}
}
ServiceHanlder.java
public class ServiceHandler {
static String response = null;
public final static int GET = 1;
public final static int POST = 2;
public ServiceHandler() {
}
/**
* Making service call
*
* #url - url to make request
* #method - http request method
*/
public static String makeServiceCall(String url, int method) {
return makeServiceCall(url, method, null);
}
/**
* Making service call
*
* #url - url to make request
* #method - http request method
* #params - http request params
*/
public static String makeServiceCall(String url, int method,
List<NameValuePair> params) {
try {
// http client
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpEntity httpEntity = null;
HttpResponse httpResponse = null;
// Checking http request method type
if (method == POST) {
HttpPost httpPost = new HttpPost(url);
// adding post params
if (params != null) {
httpPost.setEntity(new UrlEncodedFormEntity(params));
}
Log.e("Selltis Request URL", url);
httpResponse = httpClient.execute(httpPost);
} else if (method == GET) {
// appending params to url
if (params != null) {
String paramString = URLEncodedUtils
.format(params, "utf-8");
url += paramString;
Log.i("Request URL", url);
}
HttpGet httpGet = new HttpGet(url);
httpResponse = httpClient.execute(httpGet);
}
httpEntity = httpResponse.getEntity();
response = EntityUtils.toString(httpEntity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return "Fail";
} catch (ClientProtocolException e) {
e.printStackTrace();
return "Fail";
} catch (IOException e) {
e.printStackTrace();
return "Fail";
}
return response;
}
}
Interface for Load More
public interface OnLoadMoreListener {
void onLoadMore();
}
Interface to know web service data loaded from asynctask
public interface OnTaskCompleted{
void onTaskCompleted(String response);
}
Please let me know if this works or any issues for you.
Better to use Volley or okHttp Libraries for Networking.
For ImageLoading i used Glide Library.

This is how I detect whether RecyclerView should refresh by OnScrollListener, take a look at it:
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
int ydy = 0;
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int offset = dy - ydy;
ydy = dy;
boolean shouldRefresh = (linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0)
&& (recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) && offset > 30;
if (shouldRefresh) {
//swipeRefreshLayout.setRefreshing(true);
//Refresh to load data here.
return;
}
boolean shouldPullUpRefresh = linearLayoutManager.findLastCompletelyVisibleItemPosition() == linearLayoutManager.getChildCount() - 1
&& recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING && offset < -30;
if (shouldPullUpRefresh) {
//swipeRefreshLayout.setRefreshing(true);
//refresh to load data here.
return;
}
swipeRefreshLayout.setRefreshing(false);
}
});
Hope you'll be inspired. Good luck~

To implement OnScrollListener in Kotlin for RecyclerView, you can use
recyclerViewChat.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
Log.d("scroll", "idle")
} else if (newState == RecyclerView.SCROLL_STATE_SETTLING) {
Log.d("scroll", "settling")
} else if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
Log.d("scroll", "dragging")
}
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
Log.d("scroll", "scrolling")
}
})

Another example. Set you progress bar at bottom and change its visibility according to scrolling/loading and your records. Note: you need to call notifyDataSetChanged(); method to add/refresh data to adapter
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int total = linearLayoutManager.getItemCount();
int firstVisibleItemCount = linearLayoutManager.findFirstVisibleItemPosition();
int lastVisibleItemCount = linearLayoutManager.findLastVisibleItemPosition();
//to avoid multiple calls to loadMore() method
//maintain a boolean value (isLoading). if loadMore() task started set to true and completes set to false
if (!isLoading) {
if (total > 0)
if ((total - 1) == lastVisibleItemCount){
loadMore();//your HTTP stuff goes in this method
loadingProgress.setVisibility(View.VISIBLE);
}else
loadingProgress.setVisibility(View.GONE);
}
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
});

The idea to implement load-more is :
Get all records in one collection. Take another collection which will populate partial records lets say 10 records. Now, when u reach at bottom, populate next 10 records in the collection and notify the list.
So your code will be something like this :
ArrayList<NatureItem> tempList; // which holds partial records
tempList = getList(limit, 10);
mAdapter = new RecyclerViewMaterialAdapter(new CardAdapter(getActivity(), tempList), 2);
mRecyclerView.setAdapter(mAdapter);
Now, code to load next records :
limit += 10;
tempList.addAll(getList(limit, 10));
mAdapter.notifyDataSetChanged();
To show he loader/progress, better to use load-more library

In the onScroll method
if (!loading && (totalItemCount - visibleItemCount)
<= (firstVisibleItem + visibleThreshold)) {
// End has been reached
Log.i("...", "end called");
// Do something
new JSONAsyncTask().execute("http://walldroidhd.com/api.php");
loading = true;
}

Now accepted answer as #SilentKnight suggested will not work as setOnscroll is deprecated by Android SDK.
You should use
recyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
int ydy = 0;
#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);
int offset = dy - ydy;
ydy = dy;
boolean shouldRefresh = (linearLayoutManager.findFirstCompletelyVisibleItemPosition() == 0)
&& (recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) && offset > 30;
if (shouldRefresh) {
//swipeRefreshLayout.setRefreshing(true);
//Refresh to load data here.
return;
}
boolean shouldPullUpRefresh = linearLayoutManager.findLastCompletelyVisibleItemPosition() == linearLayoutManager.getChildCount() - 1
&& recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING && offset < -30;
if (shouldPullUpRefresh) {
//swipeRefreshLayout.setRefreshing(true);
//refresh to load data here.
return;
}
swipeRefreshLayout.setRefreshing(false);
}
});

Related

How to handle pagination/load more in Retrofit 2.0?

I haven't found yet the proper examples of how to make an app load more items from Retrofit onResponse while scrolling down the RecyclerView.
Here is how I'm loading my fist 20 items:
List<ModelPartners> model = new ArrayList<>();
Call<ResponsePartners> call = ApiClient.getRetrofit().getPartnerList(params);
call.enqueue(this);
My RecyclerView
PartnersAdapter adapter = new PartnersAdapter(getContext(), recyclerView, model);
recyclerView.setAdapter(adapter);
And here is my Retrofit onResponse:
#Override
public void onResponse(Call<ResponsePartners> call, Response<ResponsePartners> response) {
if (getActivity() != null && response.isSuccessful()) {
List<ModelPartners> body = response.body().getData();
//Rest of the code to add body to my Adapter and notifyDataSetChanged
}
}
My Problem is, every time I add the method to load more items on scroll, onResponse keeps loading non-stop till the last page. Even if I have put set loading to false.
Can someone please show how to properly use pagination in Retrofit? What libraries you used with Retrofit or show me how you did it your way? Thank you in advance
You need three things to achieve this, you need:
You need an onscroll listener for the recycler view.
You need a method to add new items to the recycler adapter
You need to call your paginated endpoint
Assuming you have a model like this from the server
public class PagedList<T> {
private int page = 0;
private List<T> results = new ArrayList<>();
private int totalResults = 0;
private int totalPages = 0;
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public List<T> getResults() {
return results;
}
public void setResults(List<T> results) {
this.results = results;
}
public int getTotalResults() {
return totalResults;
}
public void setTotalResults(int totalResults) {
this.totalResults = totalResults;
}
public int getTotalPages() {
return totalPages;
}
public void setTotalPages(int totalPages) {
this.totalPages = totalPages;
}
}
Your OnScroll Listener: -
In your activity this is what you would have, so add the second method to your activity
public void onCreate(Bundle savedInstance) {
// setup your view components
// ...
// get the layout manager
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
// rest endpoint
apiEndpoint = retrofit.create(RetrofitEndpoint.class);
// initialise loading state
mIsLoading = false;
mIsLastPage = false;
// amount of items you want to load per page
final int pageSize = 20;
// set up scroll listener
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// number of visible items
int visibleItemCount = layoutManager.getChildCount();
// number of items in layout
int totalItemCount = layoutManager.getItemCount();
// the position of first visible item
int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();
boolean isNotLoadingAndNotLastPage = !mIsLoading && !mIsLastPage;
// flag if number of visible items is at the last
boolean isAtLastItem = firstVisibleItemPosition + visibleItemCount >= totalItemCount;
// validate non negative values
boolean isValidFirstItem = firstVisibleItemPosition >= 0;
// validate total items are more than possible visible items
boolean totalIsMoreThanVisible = totalItemCount >= pageSize;
// flag to know whether to load more
boolean shouldLoadMore = isValidFirstItem && isAtLastItem && totalIsMoreThanVisible && isNotLoadingAndNotLastPage
if (shouldLoadMore) loadMoreItems(false);
}
});
// load the first page
loadMoreItems(true);
}
private void loadMoreItems(boolean isFirstPage) {
// change loading state
mIsLoading = true;
mCurrentPage = mCurrentPage + 1;
// update recycler adapter with next page
apiEndpoint.getPagedList(mCurrentPage).enqueue(new Callback<PagedList<Object>>() {
#Override
public void onResponse(Call<PagedList<Object>> call, Response<PagedList<Object>> response) {
PagedList<Object> result = response.body();
if (result == null) return;
else if (!isFirstPage) mAdapter.addAll(result.getResults());
else mAdapter.setList(result.getResults());
mIsLoading = false;
mIsLastPage = mCurrentPage == result.getTotalPages();
}
#Override
public void onFailure(Call<PagedList<Object>> call, Throwable t) {
Log.e("SomeActivity", t.getMessage());
}
});
}
Recycler Adapter: -
For the recycler adapter all you need is to add a method that adds items to its list, as below
public class SomeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Object> list;
// .. other overridden members
public void setList(List<Object> list) {
this.list = list;
notifyDataSetChanged();
}
public void addAll(List<Object> newList) {
int lastIndex = list.size() - 1;
list.addAll(newList);
notifyItemRangeInserted(lastIndex, newList.size());
}
}
Then finally your retrofit interface that takes the page, as below:
interface RetrofitEndpoint {
#GET("paged/list/endpoint")
Call<PagedList<Object>> getPagedList(#Query("page") int page);
}
Hope that helps.
#Alimov Shohrukh, I also tried for many ways for Pagination
1) Check this link,This is one way
2) I mention it step by step
from API side - you need to pass pageConunt, pageIndex and get data based on above parameters
pageConunt - means how many data you want get from server for i.e - 10
pageIndex - page number for i.e 1,2,3 etc
public class DemoActivity extends BaseActivity{
List<BaseModel> orderList = new ArrayList<>();
ListAdapter listAdapter;
LinearLayoutManager layoutManager;
OrderListAdapter orderListAdapter;
int pageIndex = 1; // you can pass 1,2,3...
int pageCount = 10; //you can pass 10,20...
boolean isApiSuccess = false;
//if api get success == true then you need to work with load more sp we take one boolean variable
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
findView();
setRecyclerViewPagination();
}
private void findView() {
//recyclerview
rv_po_order_number = findViewById(R.id.rv_po_order_number);
}
//custom OnScrollListener
private RecyclerView.OnScrollListener recyclerViewOnScrollListener = new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (isApiSuccess) {
pageIndex++;
listTestApiCall(pageIndex, searchQuery);
Log.e(TAG, pageIndex + " page count ");
orderListAdapter.showLoading(true);
rv_po_order_number.post(new Runnable() {
public void run() {
// There is no need to use notifyDataSetChanged()
orderListAdapter.notifyDataSetChanged();
}
});
}
}
};
private void setRecyclerViewPagination() {
orderList = new ArrayList<>();
orderListAdapter = new OrderListAdapter(mActivity, orderList);
layoutManager = new LinearLayoutManager(mActivity, LinearLayoutManager.VERTICAL, false);
rv_po_order_number.setLayoutManager(layoutManager);
rv_po_order_number.setHasFixedSize(true);
rv_po_order_number.setAdapter(orderListAdapter);
rv_po_order_number.addOnScrollListener(recyclerViewOnScrollListener);
listTestApiCall(pageCount,pageIndex);
}
private void listTestApiCall(final int pageCount,final int pageIndex) {
// if (CommonUtils.isConnectingToInternet(mActivity)) {
if (validateInternetConn(mActivity)) {//check internet
final boolean isFirstPage = pageIndex == 1 ? true : false;
if (isFirstPage)
//do your stuff - if you want to show loader
Call<BaseModel> call = ApiClient.getClient().listApiCall(pageCount, pageIndex);
call.enqueue(new Callback<BaseModel>() {
#Override
public void onResponse(Call<BaseModel> call, Response<BaseModel> response) {
try {
if (response.isSuccessful()) {
boolean success = response.body().getStatus();
isApiSuccess = response.body().getStatus();
if (success) {
List<BaseModel> list = new ArrayList<>();
if (response.body().getData() != null) {
list = response.body().getData();
if (isFirstPage)
orderList.clear();
orderList.addAll(response.body().getData());
}
if (list != null && list.size() > 0) {
isApiSuccess = true;
} else {
isApiSuccess = false;
}
} else if (!success) {
isApiSuccess = false;
String message = response.body().getMessage();
}
listAdapter.showLoading(false);
listAdapter.notifyDataSetChanged();
}
} catch (Exception e) {
e.printStackTrace();
Log.e("Tag", "error=" + e.toString());
isApiSuccess = false;
}
}
#Override
public void onFailure(Call<BaseModel> call, Throwable t) {
Log.e("Tag", "error" + t.toString());
isApiSuccess = false;
}
});
}
}
}
here is OrderListAdapter
public class OrderListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
Activity mActivity;
List<OrderListBaseModel.DataBean> mList;
PurchaseOrderReceiveOnClick purchaseOrderReceiveOnClick;
DeleteUpdatePOOnClick deleteUpdatePOOnClick;
public static final int TYPE_FOOTER = 1;
public static final int TYPE_ITEM = 2;
protected boolean showLoader = true;
public OrderListAdapter(Activity mActivity, List<OrderListBaseModel.DataBean> mList, PurchaseOrderReceiveOnClick purchaseOrderReceiveOnClick,DeleteUpdatePOOnClick deleteUpdatePOOnClick) {
this.mActivity = mActivity;
this.purchaseOrderReceiveOnClick = purchaseOrderReceiveOnClick;
this.deleteUpdatePOOnClick = deleteUpdatePOOnClick;
this.mList = mList;
}
public OrderListAdapter(Activity mActivity, List<OrderListBaseModel.DataBean> mList) {
this.mActivity = mActivity;
this.mList = mList;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_ITEM) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.row_purchase_order_receive, parent, false);
return new DataViewHolder(v, purchaseOrderReceiveOnClick);
} else if (viewType == TYPE_FOOTER) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.loading_layout, parent, false);
return new FooterViewHolder(v);
} else
return null;
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof DataViewHolder) {
final DataViewHolder dataViewHolder = (DataViewHolder) holder;
final OrderListBaseModel.DataBean dataBean = getItem(position);
if (dataBean != null) {
dataViewHolder.setPosition(position);
dataViewHolder.setSingleBean(dataBean);
}
}
}
private OrderListBaseModel.DataBean getItem(int position) {
if (mList.size() > 0)
return mList.get(position);
else
return null;
}
public void showLoading(boolean status) {
showLoader = status;
}
#Override
public int getItemViewType(int position) {
if ((position == mList.size() - 1) && showLoader) {
return TYPE_FOOTER;
}
return TYPE_ITEM;
}
public void removeItem(int position) {
mList.remove(position);
notifyItemRemoved(position);
}
#Override
public int getItemCount() {
return mList.size();
}
public static class DataViewHolder extends RecyclerView.ViewHolder {
int position;
OrderListBaseModel.DataBean dataBean;
private TextView tv_row_po_no,textViewOptions;
public DataViewHolder(View v, final PurchaseOrderReceiveOnClick purchaseOrderReceiveOnClick) {
super(v);
tv_row_po_no = v.findViewById(R.id.tv_row_po_no);
textViewOptions = v.findViewById(R.id.textViewOptions);
}
public void setPosition(int position) {
this.position = position;
}
public void setSingleBean(OrderListBaseModel.DataBean dataBean) {
this.dataBean = dataBean;
}
}
private class FooterViewHolder extends RecyclerView.ViewHolder {
public FooterViewHolder(View view) {
super(view);
}
}
}
here is xml code
loading_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/linearRoot"
android:gravity="center_horizontal"
android:layout_marginTop="#dimen/_5sdp">
<com.app.trackpoint.custom_loader.MYLoader
android:layout_width="#dimen/_30sdp"
app:my_color="#color/colorAccent"
android:layout_height="#dimen/_30sdp" />
</LinearLayout>

Android recycler view on scroll

I want to load more contents from my adapter while scrolling the recycler view.I implemented it, but its not working. my recycler view works perfectly, but I am not able to load rest of the contents from my list while scrolling. Presently there is no error in my code. but I couldn't load more items while scrolling. please help.
This is my main activity.
public class Contact_school extends AppCompatActivity implements SearchView.OnQueryTextListener {
private List<Contact> Listcontact = new ArrayList<>();
Contacts_Adapter cadapter;
private RecyclerView rv;
public String GET_CONTACTS = "http://xyzx.com/Publicpages_mob/brief_school_details";
public Contact contact;
public String school_id;
String tag_json_obj = "json_obj_req";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contact_school);
rv = (RecyclerView) findViewById(R.id.recycler_view);
preparelist();
cadapter = new Contacts_Adapter(Listcontact, rv);
final LinearLayoutManager layoutManager = new LinearLayoutManager(Contact_school.this);
rv.setLayoutManager(layoutManager);
rv.setItemAnimator(new DefaultItemAnimator());
rv.setAdapter(cadapter);
rv.setHasFixedSize(true);
cadapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
Log.v(" KILILII ", "KITTTI");
//add null , so the adapter will check view_type and show progress bar at bottom
//// Listcontact.add(null);
//// cadapter.notifyItemInserted(Listcontact.size() - 1);
// remove progress item
//// Listcontact.remove(Listcontact.size() - 1);
//// cadapter.notifyItemRemoved(Listcontact.size());
// //add items one by one
int start = Listcontact.size();
int end = start + 20;
for (int i = start + 1; i <= end; i++) {
Listcontact.add(contact);
cadapter.notifyItemInserted(Listcontact.size());
}
cadapter.setLoaded();
//or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged();
}
});
}
private void preparelist() {
final StringRequest strReq = new StringRequest(Request.Method.POST, GET_CONTACTS, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jObj = new JSONObject(response);
Log.e("RESPONSE TEST", "" + jObj);
JSONArray jsonArray = jObj.getJSONArray("school_details");
Log.e("RESPONSE ARRAY", "" + jsonArray);
Log.d("SUCESS ", response);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonobject = jsonArray.getJSONObject(i);
contact = new Contact();
contact.setAddress(jsonobject.getString("school_address"));
contact.setRating(jsonobject.getString("school_rating"));
Listcontact.add(contact);
}
cadapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("Error", "Registration Error: " + error.getMessage());
Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_LONG).show();
}
})
{
#Override
protected Map<String, String> getParams() {
// Posting params to register url
Map<String, String> params = new HashMap<String, String>();
return params;
}
};
AppController.getInstance().addToRequestQueue(strReq, tag_json_obj);
}
this is my adapter class
public class Contacts_Adapter extends RecyclerView.Adapter<Contacts_Adapter.MyViewHolder> {
private List<Contact> List1;
private final int VIEW_ITEM = 1;
private final int VIEW_PROG = 0;
private int visibleThreshold = 5;
private int lastVisibleItem, totalItemCount;
private boolean loading;
private OnLoadMoreListener onLoadMoreListener;
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView text_address,text_rating;
public MyViewHolder(View view) {
super(view);
text_address = (TextView)view.findViewById(R.id.textaddress);
text_rating = (TextView)view.findViewById(R.id.textrating);
}
}
public Contacts_Adapter(List<Contact> List1,RecyclerView recyclerView)
{
this.List1 = List1;
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 List1.get(position) != null ? VIEW_ITEM : VIEW_PROG;
}
#Override
public Contacts_Adapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
Contact c = List1.get(position);
holder.text_rating.setText("Rating "+c.getRating());
holder.text_address.setText(c.getAddress());
}
public void setLoaded() {
loading = false;
}
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
this.onLoadMoreListener = onLoadMoreListener;
}
this is my model class
public class Contact implements Serializable {
private static final long serialVersionUID = 1L;
private String address,rating;
public Contact(){
}
public Contact (String address, String rating){
this.address = address;
this.rating= rating;
}
public String getAddress(){ return address;}
public String getRating( ){return rating;}
public void setAddress(String ad){ this.address= ad;}
public void setRating(String ad){ this.rating= ad;}
}
and I have this interface
public interface OnLoadMoreListener {
void onLoadMore();
}
please help
You don't need to track the scroll to know when to search more itens.
You can call the Volley request from the onBindViewHolder, for example:
int itemsBeforeUpdate = 10;
public void onBindViewHolder(MyViewHolder holder, final int position) {
Contact c = List1.get(position);
holder.text_rating.setText("Rating "+c.getRating());
holder.text_address.setText(c.getAddress());
if(List1.size() - position <10){
// Do your Volley Request, add response to the list and notify the adapter that the data changed
}
}
Instead of calling OnLoadMoreListener in the following block
if (!loading && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
// End has been reached
// Do something
if (onLoadMoreListener != null) {
onLoadMoreListener.onLoadMore();
}
loading = true;
}
Just perform your load more request in this block only. Like:
if (!loading&& totalItemCount <= (lastVisibleItem + visibleThreshold)) {
// Load your volley request or load more request her
loading = true;
}
and after that notify the adapter that data has been changed.
Instead of adding the values to the list in the activity class, try it by adding it to the adapter class. Say for example add an method in adapter like below.
public void addContact(Contact contact) {
list.add(contact);
notifyItemInserted(list.size());
}
And in the activity instead of this,
YOUR CODE:
cadapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
Log.v(" KILILII ", "KITTTI");
//add null , so the adapter will check view_type and show progress bar at bottom
//// Listcontact.add(null);
//// cadapter.notifyItemInserted(Listcontact.size() - 1);
// remove progress item
//// Listcontact.remove(Listcontact.size() - 1);
//// cadapter.notifyItemRemoved(Listcontact.size());
// //add items one by one
int start = Listcontact.size();
int end = start + 20;
for (int i = start + 1; i <= end; i++) {
Listcontact.add(contact);
cadapter.notifyItemInserted(Listcontact.size());
}
cadapter.setLoaded();
//or you can add all at once but do not forget to call mAdapter.notifyDataSetChanged();
}
});
TRY THIS:
cadapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
Log.v(" KILILII ", "KITTTI");
int start = Listcontact.size();
int end = start + 20;
for (int i = start + 1; i <= end; i++) {
cadapter.addContact(contact);
}
cadapter.setLoaded();
}
});
Hope this helpful :)

Set last position when scroll load more recycleview

I am trying to implement load more recycleview It's working fine but when scroll recycleview at that time always first item is top of the view, I want next scrollable item at the top, How can I solve this problem, Please help me
MainActivity.java
public class MainActivity extends AppCompatActivity {
private int page_no = 0;
private RecyclerView mRecyclerView;
private ArrayList<NotificationBean> mUsers = new ArrayList<>();
private UserAdapter mUserAdapter;
private NotificationBean mNotificationBean;
private int loadMoreArrayListSize;
public int arrayListSize;
// private LinearLayoutManager mLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mUsers = new ArrayList<>();
mRecyclerView = (RecyclerView) findViewById(R.id.recycleView);
// mLayoutManager = new LinearLayoutManager(this);
// mRecyclerView.setLayoutManager(mLayoutManager);
getData(MainActivity.this, page_no, "4");
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mUserAdapter = new UserAdapter();
mUserAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
Log.e("haint", "Load More");
mUsers.add(null);
mUserAdapter.notifyItemInserted(mUsers.size() - 1);
//Load more data for reyclerview
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Log.e("haint", "Load More 2");
//Remove loading item
mUsers.remove(mUsers.size() - 1);
mUserAdapter.notifyItemRemoved(mUsers.size());
//Load data
page_no++;
//callAPI(1);
// Log.d("arrTemp Position: : ", String.valueOf(arrTemp));
getData(MainActivity.this, page_no, "4");
// mLayoutManager.scrollToPositionWithOffset(mUsers.size() - 10, 0);
Log.v("LoadMoreListener arsize", Integer.toString(mUsers.size()));
loadMoreArrayListSize = arrayListSize - mUsers.size();
Log.v("loadMoreArrayListSize", Integer.toString(loadMoreArrayListSize));
}
}, 5000);
}
});
}
static class UserViewHolder extends RecyclerView.ViewHolder {
public ImageView imgView;
public TextView txtComment, txtParamLink, txtTitle, txtVideoId;
public UserViewHolder(View itemView) {
super(itemView);
txtComment = (TextView) itemView.findViewById(R.id.txtComment);
txtParamLink = (TextView) itemView.findViewById(R.id.txtParamLink);
txtTitle = (TextView) itemView.findViewById(R.id.txtTitle);
txtVideoId = (TextView) itemView.findViewById(R.id.txtVideoId);
imgView = (ImageView) itemView.findViewById(R.id.imgView);
}
}
static class LoadingViewHolder extends RecyclerView.ViewHolder {
public ProgressBar progressBar;
public LoadingViewHolder(View itemView) {
super(itemView);
progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar1);
}
}
class UserAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_LOADING = 1;
private OnLoadMoreListener mOnLoadMoreListener;
private boolean isLoading;
private int visibleThreshold = 5;
private int lastVisibleItem, totalItemCount;
public UserAdapter() {
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
mRecyclerView.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 (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMore();
}
isLoading = true;
}
}
});
}
public void setOnLoadMoreListener(OnLoadMoreListener mOnLoadMoreListener) {
this.mOnLoadMoreListener = mOnLoadMoreListener;
}
#Override
public int getItemViewType(int position) {
return mUsers.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.notification_item, parent, false);
return new UserViewHolder(view);
} else if (viewType == VIEW_TYPE_LOADING) {
View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.layout_loading_item, parent, false);
return new LoadingViewHolder(view);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof UserViewHolder) {
NotificationBean user = mUsers.get(position);
UserViewHolder userViewHolder = (UserViewHolder) holder;
// userViewHolder.tvName.setText(user.getName());
// userViewHolder.tvEmailId.setText(user.getEmail());
userViewHolder.txtComment.setText(Integer.toString(user.getComment()));
userViewHolder.txtParamLink.setText(user.getPermalink());
userViewHolder.txtTitle.setText(user.getTitle());
userViewHolder.txtVideoId.setText(user.getVideoid());
if (user.getImage() != null) {
Glide.with(MainActivity.this).load(user.getImage()).placeholder(R.mipmap.ic_launcher).error(R.mipmap.ic_launcher).dontAnimate().into(userViewHolder.imgView);
}
} else if (holder instanceof LoadingViewHolder) {
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
loadingViewHolder.progressBar.setIndeterminate(true);
}
}
#Override
public int getItemCount() {
return mUsers == null ? 0 : mUsers.size();
}
public void setLoaded() {
isLoading = false;
}
}
private void getData(Context context, final int posts_per_page, final String type) {
// final ProgressDialog pDialog = new ProgressDialog(this);
// pDialog.setMessage("Loading...");
// pDialog.show();
RequestQueue queue = Volley.newRequestQueue(context);
// StringRequest sr = new StringRequest(Request.Method.POST, "http://asiatube.info/sgtube/api/ws.php", new Response.Listener<String>() {
StringRequest sr = new StringRequest(Request.Method.POST, "http://steanrewards.com/api/ws.php", new Response.Listener<String>() {
#Override
public void onResponse(String response) {
JSONArray jArray;
JSONArray jsonArray = null;
JSONObject jsonObject = null;
try {
jArray = new JSONArray(response);
JSONObject jObj = jArray.getJSONObject(0);
int code = jObj.getInt("code");
if (code == 0) {
Log.d("allcount:: :: ::", String.valueOf(jObj.optInt("allcount")));
if (jObj.has("result")) {
jsonArray = jObj.getJSONArray("result");
Log.d("EVENTLIST ARRAY=", jsonArray.length() + "");
if (jsonArray != null && jsonArray.length() > 0) {
// arrTemp = new ArrayList<>();
for (int i = 0; i < jsonArray.length(); i++) {
jsonObject = jsonArray.getJSONObject(i);
mNotificationBean = new NotificationBean();
mNotificationBean.id = jsonObject.getString("id");
mNotificationBean.permalink = jsonObject.getString("permalink");
mNotificationBean.image = jsonObject.getString("image");
mNotificationBean.title = jsonObject.getString("title");
mNotificationBean.videotype = jsonObject.getString("videotype");
mNotificationBean.videoid = jsonObject.getString("videoid");
mNotificationBean.desc = jsonObject.getString("desc");
mNotificationBean.author_url = jsonObject.getString("author_url");
mNotificationBean.like = jsonObject.getString("like");
mNotificationBean.unlike = jsonObject.getString("unlike");
mNotificationBean.comment = jsonObject.getInt("comment");
//arrTemp.add(mNotificationBean);
mUsers.add(mNotificationBean);
Log.v("ArrayList Size:: :: ", Integer.toString(mUsers.size()));
mRecyclerView.setAdapter(mUserAdapter);
mUserAdapter.notifyDataSetChanged();
mUserAdapter.setLoaded();
}
Log.v("mUsers Size:: :: ", Integer.toString(mUsers.size()));
arrayListSize = mUsers.size();
}
//mAdapter.notifyDataSetChanged();
// mAdapter = new NotificationAdapter(mArrayList);
// pDialog.dismiss();
}
} else {
// pDialog.dismiss();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MainActivity.this, "Check internet connection", Toast.LENGTH_LONG).show();
}
}) {
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put("posts_per_page", Integer.toString(posts_per_page));
params.put("type", type);
// params.put("fromsite", fromsite);
return params;
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Content-Type", "application/x-www-form-urlencoded");
return params;
}
};
sr.setRetryPolicy(new DefaultRetryPolicy(
15000,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
queue.add(sr);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycleView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp" />
</LinearLayout>
When you are loading you must be knowing the position of top element of new loaded items. just call:
recyclerView.scrollToPosition(position);
And you can use it whenever you want to show specific item on current view, just call this function with their list position. For example you are loading new item after every 80 items so, position of newly loaded item will be 80 so you can call:
recyclerView.scrollToPosition(80);
Just keep on updating this position as you load more and more items.
although,recyclerView.scrollToPosition(position); is a quick fix i would suggest you don't use it, genrally this happens when you do setAdapter() again after the pagination, you need to call notifyDataSetChanged after the new data is got

How to implement load more recyclerview in android

I want to implement load more in Recyclerview. Here is the code.
The code is from github. https://gist.github.com/ssinss/e06f12ef66c51252563e
MainActivity code:
package com.example.tatson.bila;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.Volley;
import com.example.tatson.bila.CardAdapter;
import com.example.tatson.bila.Config;
import com.example.tatson.bila.SuperHeroes;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Text;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements SwipeRefreshLayout.OnRefreshListener{
SwipeRefreshLayout swipeLayout;
LinearLayoutManager mLayoutManager;
// initially offset will be 0, later will be updated while parsing the json
private int offSet = 0;
private int previousTotal = 0;
int pastVisiblesItems, visibleItemCount, totalItemCount;
private boolean loading = true; // True if we are still waiting for the last set of data to load.
private int visibleThreshold = 5; // The minimum amount of items to have below your current scroll position before loading more.
int firstVisibleItem;
private int current_page = 1;
//Creating a List of superheroes
private List<SuperHeroes> listSuperHeroes;
//Creating Views
private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
private RecyclerView.Adapter adapter;
public String Img;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Initializing Views
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
//Initializing our superheroes list
listSuperHeroes = new ArrayList<>();
mLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(mLayoutManager);
swipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_container);
swipeLayout.setOnRefreshListener(this);
swipeLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
android.R.color.holo_green_light,
android.R.color.holo_orange_light,
android.R.color.holo_red_light);
swipeLayout.post(new Runnable() {
#Override
public void run() {
swipeLayout.setRefreshing(true);
getData();
}
}
);
recyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener(linearLayoutManager) {
#Override
public void onLoadMore(int current_page) {
Log.d("End","Sucess");
}
});
}
//This method will get data from the web api
private void getData(){
//Showing a progress dialog
// final ProgressDialog loading = ProgressDialog.show(this,"Loading Data", "Please wait...",false,false);
// appending offset to url
String url = Config.DATA_URL;
String url1 = url + offSet;
//Creating a json array request
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(url1,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
//Dismissing progress dialog
// loading.dismiss();
//calling method to parse json array
parseData(response);
adapter.notifyDataSetChanged();
// stopping swipe refresh
swipeLayout.setRefreshing(false);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
//Creating request queue
RequestQueue requestQueue = Volley.newRequestQueue(this);
//Adding request to the queue
requestQueue.add(jsonArrayRequest);
}
//This method will parse json data
private void parseData(JSONArray array){
for(int i = 0; i<array.length(); i++) {
SuperHeroes superHero = new SuperHeroes();
CardAdapter car = new CardAdapter();
JSONObject json = null;
try {
json = array.getJSONObject(i);
superHero.setImageUrl(json.getString(Config.TAG_IMAGE_URL));
Img =json.getString(Config.TAG_IMAGE_URL);
superHero.setName(json.getString(Config.TAG_NAME));
superHero.setRank(json.getInt(Config.TAG_RANK));
// superHero.setRealName(json.getString(Config.TAG_REAL_NAME));
//superHero.setCreatedBy(json.getString(Config.TAG_CREATED_BY));
//superHero.setFirstAppearance(json.getString(Config.TAG_FIRST_APPEARANCE));
int rank = json.getInt("pid");
// updating offset value to highest value
if (rank >= offSet)
offSet = rank;
// ArrayList<String> powers = new ArrayList<String>();
//JSONArray jsonArray = json.getJSONArray(Config.TAG_POWERS);
/* for(int j = 0; j<jsonArray.length(); j++){
powers.add(((String) jsonArray.get(j))+"\n");
}*/
//superHero.setPowers(powers);
Log.d("test",Img);
car.setImageUrl(Img);
} catch (JSONException e) {
e.printStackTrace();
}
listSuperHeroes.add(superHero);
}
//Finally initializing our adapter
adapter = new CardAdapter(listSuperHeroes, this);
//Adding adapter to recyclerview
recyclerView.setAdapter(adapter);
}
#Override
public void onRefresh() {
listSuperHeroes.clear();
refreshItems();
}
void refreshItems() {
// Load items
getData();
// Load complete
onItemsLoadComplete();
}
void onItemsLoadComplete() {
// Update the adapter and notify data set changed
adapter.notifyDataSetChanged();
//Finally initializing our adapter
adapter = new CardAdapter(listSuperHeroes, this);
//Adding adapter to recyclerview
recyclerView.setAdapter(adapter);
// Stop refresh animation
}
}
EndlessRecyclerOnScrollListener class code:
package com.example.tatson.bila;
/**
* Created by Tatson on 23-11-2015.
*/
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
public abstract class EndlessRecyclerOnScrollListener extends RecyclerView.OnScrollListener {
public static String TAG = EndlessRecyclerOnScrollListener.class.getSimpleName();
private int previousTotal = 0; // The total number of items in the dataset after the last load
private boolean loading = true; // True if we are still waiting for the last set of data to load.
private int visibleThreshold = 5; // The minimum amount of items to have below your current scroll position before loading more.
int firstVisibleItem, visibleItemCount, totalItemCount;
private int current_page = 1;
private LinearLayoutManager mLinearLayoutManager;
public EndlessRecyclerOnScrollListener(LinearLayoutManager linearLayoutManager) {
this.mLinearLayoutManager = linearLayoutManager;
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = recyclerView.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading ) {
// End has been reached
// Do something
current_page++;
Log.d("End", "Sucess");
onLoadMore(current_page);
loading = true;
}
}
public abstract void onLoadMore(int current_page);
}
Thank you.
I found an answer here that, I believe, is much better than most I've seen on SO and elsewhere.
The idea is simple: in onScrolled in your RecyclerView's ScrollListener, check if the last completely visible item is the last item in your data set.
if(llm.findLastCompletelyVisibleItemPosition() == data.length() -1){
//bottom of list!
loadMoreData();
}
This happens with a method in the LinearLayoutManager. Calling LinearLayoutManager#findLastCompletelyVisibleItemPosition() can comparing it to the position of the last item in your dataset let's you know when you can load more.
I haven't tried this for the GridLayoutManager.
UPDATE
LinearLayoutManager#findLastVisibleItemPosition() is a better alternative to LinearLayoutManager#findLastCompletelyVisibleItemPosition(), especially when your items are longer than the window height.
Check do you currently have items to scroll down -
if (! recyclerView.canScrollVertically(1))
If yes - load more items, for example, using HTTP client.
Full code:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (! recyclerView.canScrollVertically(1)){ //1 for down
loadMore();
}
}
});
In Kotlin you can use the below code snippet.
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if(!recyclerView.canScrollVertically(1)) {
// LOAD MORE
}
}
})
Try this....
static boolean loadmore=true;
LinearLayoutManager layoutManager = ((LinearLayoutManager)recyclerView.getLayoutManager());
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
// super.onScrolled(recyclerView, dx, dy);
int lastVisiblePosition = layoutManager.findLastVisibleItemPosition();
if (lastVisiblePosition == recyclerView.getChildCount()) {
if (loadmore) {
loadmore = false;
method();
}
}
}
});
private void method(){
loadmore=true;
}
Adding to the accepted answer:
It's a better user experience if the scrolling doesn't stop before new data is loaded. Therefore you should load new data before the very last item is reached.
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
// already load new data if there are only 2 items left to scroll
if (llm.findLastCompletelyVisibleItemPosition() >= dataList.size()-3 && !alreadyLoadedAllData) {
loadNewData();
}
}
});
llm is your LinearLayoutManager and alreadyLoadedAllData.
public abstract class LoadMoreAdapter extends RecyclerView.Adapter{
private LoadMoreListner loadMoreListner;
private boolean isLoading;
int vissibleThreshold = 5;
public LoadMoreAdapter(final LoadMoreListner loadMoreListner, RecyclerView recyclerView) {
this.loadMoreListner = loadMoreListner;
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int totalItemCOunt = linearLayoutManager.getItemCount();
int lastVissibleItemPOs = linearLayoutManager.findLastVisibleItemPosition();
if (!isLoading && totalItemCOunt<= lastVissibleItemPOs+vissibleThreshold){
if (loadMoreListner!=null){
isLoading = true;
loadMoreListner.onLoadMore();
}
}
}
});
}
public void setLoaded(){
isLoading =false;
}
}
Your adapter will extends to this LoadmoreAdapter
public interface LoadMoreListner {
void onLoadMore();
}
And in your activity
#Override
public void onLoadMore() {
items.add(null);
nameLoadMoreAdapter.notifyItemInserted(items.size()-1);
loadNewData();
}
After populating list and here your loadnewData() will have this
items.remove(items.size()-1);
nameLoadMoreAdapter.notifyItemRemoved(items.size());
items.addAll(itemsArrayList);
nameLoadMoreAdapter.notifyItemInserted(items.size());
nameLoadMoreAdapter.setLoaded();
where itemsArrayList are of newdata
This links may help you .for load-moreRrecyclerview you need to change. and implement using
Link
or library
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* Created by CRAFT BOX on 9/7/2016.
*/
public class RecyclerViewPositionHelper {
final RecyclerView recyclerView;
final RecyclerView.LayoutManager layoutManager;
RecyclerViewPositionHelper(RecyclerView recyclerView) {
this.recyclerView = recyclerView;
this.layoutManager = recyclerView.getLayoutManager();
}
public static RecyclerViewPositionHelper createHelper(RecyclerView recyclerView) {
if (recyclerView == null) {
throw new NullPointerException("Recycler View is null");
}
return new RecyclerViewPositionHelper(recyclerView);
}
/**
* Returns the adapter item count.
*
* #return The total number on items in a layout manager
*/
public int getItemCount() {
return layoutManager == null ? 0 : layoutManager.getItemCount();
}
/**
* Returns the adapter position of the first visible view. This position does not include
* adapter changes that were dispatched after the last layout pass.
*
* #return The adapter position of the first visible item or {#link RecyclerView#NO_POSITION} if
* there aren't any visible items.
*/
public int findFirstVisibleItemPosition() {
final View child = findOneVisibleChild(0, layoutManager.getChildCount(), false, true);
return child == null ? RecyclerView.NO_POSITION : recyclerView.getChildAdapterPosition(child);
}
/**
* Returns the adapter position of the first fully visible view. This position does not include
* adapter changes that were dispatched after the last layout pass.
*
* #return The adapter position of the first fully visible item or
* {#link RecyclerView#NO_POSITION} if there aren't any visible items.
*/
public int findFirstCompletelyVisibleItemPosition() {
final View child = findOneVisibleChild(0, layoutManager.getChildCount(), true, false);
return child == null ? RecyclerView.NO_POSITION : recyclerView.getChildAdapterPosition(child);
}
/**
* Returns the adapter position of the last visible view. This position does not include
* adapter changes that were dispatched after the last layout pass.
*
* #return The adapter position of the last visible view or {#link RecyclerView#NO_POSITION} if
* there aren't any visible items
*/
public int findLastVisibleItemPosition() {
final View child = findOneVisibleChild(layoutManager.getChildCount() - 1, -1, false, true);
return child == null ? RecyclerView.NO_POSITION : recyclerView.getChildAdapterPosition(child);
}
/**
* Returns the adapter position of the last fully visible view. This position does not include
* adapter changes that were dispatched after the last layout pass.
*
* #return The adapter position of the last fully visible view or
* {#link RecyclerView#NO_POSITION} if there aren't any visible items.
*/
public int findLastCompletelyVisibleItemPosition() {
final View child = findOneVisibleChild(layoutManager.getChildCount() - 1, -1, true, false);
return child == null ? RecyclerView.NO_POSITION : recyclerView.getChildAdapterPosition(child);
}
View findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible,
boolean acceptPartiallyVisible) {
OrientationHelper helper;
if (layoutManager.canScrollVertically()) {
helper = OrientationHelper.createVerticalHelper(layoutManager);
} else {
helper = OrientationHelper.createHorizontalHelper(layoutManager);
}
final int start = helper.getStartAfterPadding();
final int end = helper.getEndAfterPadding();
final int next = toIndex > fromIndex ? 1 : -1;
View partiallyVisible = null;
for (int i = fromIndex; i != toIndex; i += next) {
final View child = layoutManager.getChildAt(i);
final int childStart = helper.getDecoratedStart(child);
final int childEnd = helper.getDecoratedEnd(child);
if (childStart < end && childEnd > start) {
if (completelyVisible) {
if (childStart >= start && childEnd <= end) {
return child;
} else if (acceptPartiallyVisible && partiallyVisible == null) {
partiallyVisible = child;
}
} else {
return child;
}
}
}
return partiallyVisible;
}
}
/* NearbyModel */
/**
* Created by CRAFT BOX on 8/23/2016.
*/
public class NearbyModel {
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRate() {
return rate;
}
public void setRate(String rate) {
this.rate = rate;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getImage_path() {
return image_path;
}
public void setImage_path(String image_path) {
this.image_path = image_path;
}
String id;
String name;
String rate;
public String getDistance() {
return distance;
}
public void setDistance(String distance) {
this.distance = distance;
}
String distance;
public String getReview() {
return review;
}
public void setReview(String review) {
this.review = review;
}
String review;
String address;
public String getCategory_name() {
return category_name;
}
public void setCategory_name(String category_name) {
this.category_name = category_name;
}
String category_name;
String image_path;
public NearbyModel()
{
}
public NearbyModel(String id,String name,String rate,String distance,String review,String address,String category_name,String image_path)
{
this.id=id;
this.name=name;
this.rate=rate;
this.distance=distance;
this.review=review;
this.address=address;
this.category_name=category_name;
this.image_path=image_path;
}
}
/* My activity */
public class Search_by_shop extends Fragment {
private RecyclerView recyclerView;
ArrayList<NearbyModel> near_data;
NearAdapter adapter;
int firstVisibleItem, visibleItemCount, totalItemCount,count=0;
protected int m_PreviousTotalCount;
RecyclerViewPositionHelper mRecyclerViewHelper;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.search_by_shop_fragment, container, false);
recyclerView = (RecyclerView) rootView.findViewById(R.id.search_by_recycleview);
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
mRecyclerViewHelper = RecyclerViewPositionHelper.createHelper(recyclerView);
visibleItemCount = recyclerView.getChildCount();
totalItemCount = mRecyclerViewHelper.getItemCount();
firstVisibleItem = mRecyclerViewHelper.findFirstVisibleItemPosition();
if (totalItemCount == 0 || adapter == null)
return;
if (m_PreviousTotalCount == totalItemCount)
{
return;
}
else
{
boolean loadMore = firstVisibleItem + visibleItemCount >= totalItemCount;
if (loadMore)
{
m_PreviousTotalCount = totalItemCount;
new GetAllrestaurant().execute();
}
}
}
});
new GetAllrestaurant().execute();
return rootView;
}
public class GetAllrestaurant extends AsyncTask<String, Void, JSONObject> {
ProgressDialog pd;
#Override
protected void onPreExecute() {
super.onPreExecute();
pd = new ProgressDialog(getActivity());
pd.setTitle("Please Wait");
pd.setMessage("Loading");
pd.setCancelable(false);
pd.show();
}
#Override
protected JSONObject doInBackground(String... strings) {
UserFunction uf = new UserFunction();
JSONObject json = uf.getAllrestaurunt();
return json;
}
#Override
protected void onPostExecute(JSONObject json) {
super.onPostExecute(json);
pd.dismiss();
try {
if (json.getInt("ack") == 1) {
JSONArray json_users = json.getJSONArray("result");
// looping through All Products
for (int i = 0; i < json_users.length(); i++) {
JSONObject c = json_users.getJSONObject(i);
String id = c.getString("id");
String name = c.getString("name");
String distance = c.getString("distance");
String category = c.getString("serving_category");
String rate = c.getString("rate");
String address = c.getString("address");
String count_review = c.getString("count_review");
String image_path = c.getString("image_path");
NearbyModel da=new NearbyModel(id,name,rate,distance,count_review,address,category,image_path);
near_data.add(da);
}
if(count==0)
{
adapter = new NearAdapter(getActivity(), near_data);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
}
else
{
adapter.notifyDataSetChanged();
}
if(json_users.length()==0)
{
count=0;
}
else
{
count+=json_users.length();
}
}
} catch (Exception e) {
Log.e("<-SubjectActException->", e.toString());
}
}
}
public class NearAdapter extends RecyclerView.Adapter<NearAdapter.ViewHolder> {
private ArrayList<NearbyModel> data;
private Context context;
public NearAdapter(Context context,ArrayList<NearbyModel> data) {
this.data = data;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, final int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_near_by, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, final int i) {
viewHolder.name.setText(data.get(i).getName());
viewHolder.distince.setText(data.get(i).getDistance());
viewHolder.review.setText(data.get(i).getReview());
viewHolder.category.setText(data.get(i).getCategory_name());
viewHolder.address.setText(data.get(i).getAddress());
viewHolder.rat.setRating(Integer.parseInt(data.get(i).getRate()));
viewHolder.vi_click.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
GlobalVariable.position=i;
Intent ik=new Intent(context,Restaurant_detail.class);
ik.putExtra("rid",""+data.get(i).getId());
startActivity(ik);
}
});
if(data.get(i).getImage_path().equals(""))
{
Picasso.with(context).load("abc").placeholder(R.drawable.load_240).into(viewHolder.img);
}
else
{
Picasso.with(context).load(data.get(i).getImage_path()).placeholder(R.drawable.load_240).into(viewHolder.img);
}
}
#Override
public int getItemCount() {
return data.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
private TextView name,distince,review,category,address;
private ImageView img;
private RatingBar rat;
CardView vi_click;
public ViewHolder(View view) {
super(view);
name = (TextView)view.findViewById(R.id.list_near_by_name);
distince = (TextView)view.findViewById(R.id.list_near_by_distince);
review = (TextView)view.findViewById(R.id.list_near_by_review);
category = (TextView)view.findViewById(R.id.list_near_by_category);
address = (TextView)view.findViewById(R.id.list_near_by_address);
img = (ImageView) view.findViewById(R.id.list_near_by_img);
rat = (RatingBar)view.findViewById(R.id.list_near_by_ratbar);
vi_click = (CardView)view.findViewById(R.id.list_near_card);
}
}
}
You can check this link for Load More RecyclerView and Bottom ProgressBar.
I have created a commonAdapter to handle loadMore
public abstract class CommonModelAdapter<T,V extends BaseModelViewHolder<T>> extends RecyclerView.Adapter<V>{
public abstract V setViewHolder(ViewGroup parent);
private Context mContext;
private List<T> items;
private List<T> copyItems;
public static final int VIEW_TYPE_PROGRESS = 0;
public static final int VIEW_TYPE_ITEM = 1;
public CommonModelAdapter(Context mContext,List<T> items){
this.mContext = mContext;
this.items = items;
copyItems = new ArrayList<>();
copyItems.addAll(items);
}
#Override
public V onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType == VIEW_TYPE_ITEM){
return setViewHolder(parent);
}
else{
return (V) new ProgressViewHolder(parent ,R.layout.item_progress_loader);
}
}
#Override
public void onBindViewHolder(V holder, int position) {
if (holder instanceof ProgressViewHolder) {
((ProgressViewHolder) holder).showProgressLoader();
}
else{
try {
holder.onBindData(items.get(position));
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public int getItemCount() {
return items.size();
}
#Override
public int getItemViewType(int position) {
if(items.get(position) == null)
return VIEW_TYPE_PROGRESS;
else
return VIEW_TYPE_ITEM;
}
public T getItemAt(int position){
return items.get(position);
}
public void setItems(List<T> newItems){
this.items = newItems;
}
}
Where BaseModelViewHolder
public abstract class BaseModelViewHolder<T extends BaseModelBO> extends RecyclerView.ViewHolder {
public abstract void onBindData(T data);
public BaseModelViewHolder(ViewGroup parent, int layoutId) {
super(LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false));
}
public <T extends View> T findViewById(#IdRes int resId) {
return (T) itemView.findViewById(resId);
}
}
LoadMoreRecyclerView
public class LoadMoreRecyclerView extends RecyclerView {
private boolean loading = true;
int pastVisiblesItems, visibleItemCount, totalItemCount;
//WrapperLinearLayout is for handling crash in RecyclerView
private WrapperLinearLayout mLayoutManager;
private Context mContext;
private OnLoadMoreListener onLoadMoreListener;
public LoadMoreRecyclerView(Context context) {
super(context);
mContext = context;
init();
}
public LoadMoreRecyclerView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
mContext = context;
init();
}
public LoadMoreRecyclerView(Context context, #Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
init();
}
private void init(){
mLayoutManager = new WrapperLinearLayout(mContext,LinearLayoutManager.VERTICAL,false);
this.setLayoutManager(mLayoutManager);
this.setItemAnimator(new DefaultItemAnimator());
this.setHasFixedSize(true);
}
#Override
public void onScrolled(int dx, int dy) {
super.onScrolled(dx, dy);
if(dy > 0) //check for scroll down
{
visibleItemCount = mLayoutManager.getChildCount();
totalItemCount = mLayoutManager.getItemCount();
pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();
if (loading)
{
if ( (visibleItemCount + pastVisiblesItems) >= totalItemCount)
{
loading = false;
Log.v("...", "Call Load More !");
if(onLoadMoreListener != null){
onLoadMoreListener.onLoadMore();
}
//Do pagination.. i.e. fetch new data
}
}
}
}
#Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
}
public void enableLoadingMore(boolean moreLoading){
loading = moreLoading;
}
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
this.onLoadMoreListener = onLoadMoreListener;
}
public void setScrolling(boolean enable){
mLayoutManager.setScrollEnabled(enable);
}
}
When you want to show progress...
mLoadMoreRecyclerView.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
{
overAllItems.add(null); //to show ProgressDialog
mAdapter.notifyDataSetChanged();
callYourService();
}
/*else{
//for reEnable calling it...
mLoadMoreRecyclerView.enableLoadingMore(true);
}*/
}
});

RecyclerView Endless Infinite Scrolling Issue

I am trying to implement Endless Infinite Scrolling with RecyclerView, but I am only getting first 10 records, not getting next 10 records and even not getting any progress while trying to scroll at bottom.
Whereas I was suppose to get next 10 records on scroll and so on... But getting only first 10 records
Here I have uploaded copy of my JSON - But i am not able to fetch data from same url, that's why i am using client's url and local host.
I am following this tutorial
Here is my complete code, May I know where I am doing mistake ?
JSON :
{
"names": [
{
"name": "Name 1"
},
{
"name": "Name 2"
},
....
{
"name": "Name 60"
}
]
}
Log:
D/name -(13759): Name 1
D/name -(13759): Name 2
.......................
D/name -(13759): Name 60
Here is my updated code, which i am using to parse JSON data
MainActivity.java: UPDATED
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();
}
I had the same issue once an I solve it using this code ...
First .. create this class
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();
}
Second .. in you activity use this
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;
}
});
This works for me .... I hope it works for you to.
Try notifyItemRangeChanged
yourCurrentList.addAll(newData);
mAdapter.notifyItemRangeChanged(yourCurretList.size() + 1, newDataSize);
I think this'll help you.
replace
private List<Student> studentList;
with
private List<Object> list;
also replace
#Override
public int getItemViewType(int position) {
return studentList.get(position) != null ? VIEW_ITEM : VIEW_PROG;
}
with
#Override
public int getItemViewType(int position) {
return list.get(position) instanceof Student ? VIEW_ITEM : VIEW_PROG;
}
for detect end of List you can using
#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
}
}
}
Also for Add Loading Item. add this code in adapter
public void addLoadingView(){
list.add(new Object());
notifyDataSetChanged();
}
1.
Getting first 11 recyclerview Items blank (And showing progress bar
continuously), see below screenshot:
Change loadData method as:
private void loadData() {
new Parser().execute("http://clienturl.com/jsons/mytest.txt");
}
2.
Whereas I was suppose to get first 10 records, and on scroll next 10
records and so on...
Change onPostExecute method of Parser as:
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);
}
And also remove following lines from onCreate method:
mAdapter = new DataAdapter(studentList, mRecyclerView);
// set the adapter object to the Recyclerview
mRecyclerView.setAdapter(mAdapter);
Try changing the
int i = start + 1; i <= end; i++
in the for loop to
int i = start + 1; i < end; i++
The <= validation adds an extra item.
Issue-1: You have created a new instance of mAdapter before setting the LayoutManager for RecyclerView. Thereby the constructor code in the DataAdapter to add ScrollListener is not executed since recyclerView.getLayoutManager() returns null:
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager){
// code to add ScrollListener is never executed
}
Fix: First set the LayoutManager for the Recyclerview and then create the adapter like below:
// 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: You have used temArray to create DataAdapter but in onLoadMore() you are using the studentList to add/remove new items, since studentList is not binded with mAdapter your changes doesn't reflect in the UI.
Fix: Declare temArray as a class level variable and use temArray to manipulate the items.
//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);
for (int i = start + 1; i < end; i++) {
studentList.add(add data here) ;
mAdapter.notifyItemInserted(studentList.size());
}
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);
}
});
ok so you inserted progress bar, and then you've removed it as well but you never inserted the next student to show...
something like studentList.add();
I hope that solved your problem... good luck..

Categories

Resources