I am using Laravel API with paginated data in Android...
I want to get auto paginated data.
e.g. data on first page load first and when I scroll down, next pages load continously!
You can use laravel default pagination method instate of get rows.
For example i want show users list:
//instate of :
$users = User::get();
//Use :
$users = User::paginate();
more info at : laravel site
https://laravel.com/docs/5.5/pagination
You can do so easily using the LengthAwarePaginator
protected function paginate(Collection $collection)
{
$rules = [
'per_page' => 'integer|min:2|max:50',
];
Validator::validate(request()->all(), $rules);
$page = LengthAwarePaginator::resolveCurrentPage();
$perPage = 15;
if (request()->has('per_page')) {
$perPage = (int) request()->per_page;
}
$results = $collection->slice(($page - 1) * $perPage, $perPage)->values();
$paginated = new LengthAwarePaginator($results, $collection->count(), $perPage, $page, [
'path' => LengthAwarePaginator::resolveCurrentPath(),
]);
$paginated->appends(request()->all());
return $paginated;
}
Make sure you import all the namespaces needed,
You can go ahead and paginate the collection thus
$collection = $this->paginate($collection);
Hope this helps
On Laravel Side
// Get Collection
$query = SomeModel::where('some_thing', "5")
->paginate(10);
return Response::json(array(
'some_result' => $query,
));
On Android Side (Retrofit Call)
#FormUrlEncoded
#POST
Call<JsonObject> getActions(
#Url String url);
On Android Side (Activity/Fragment)
public class NewTemplateActivity
extends AppCompatActivity {
// Recycler View
private SomeActionListAdapter someActionsAdapter;
private List<SomesomeActionListModel> listSomeActionModel;
private RecyclerView rv;
private Boolean isScrolling = false;
private int currentItems, totalItems, scrollOutItems;
private int pageNumber = 1;
private Boolean firstLoad = true;
private Boolean firstSearch = false;
private LinearLayoutManager manager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
// Init Recycler View
rv = findViewById(R.id.f_list_rv_list);
rv.setHasFixedSize(true);
listSomeActionModel = new ArrayList<>();
someActionsAdapter = new SomeActionListAdapter(
mContext,
listSomeActionModel);
manager = new LinearLayoutManager(mContext);
rv.setLayoutManager(manager);
rv.setAdapter(someActionsAdapter);
}
private void getSomeAction(
String url) {
if (firstLoad || firstSearch) {
listSomeActionModel.clear();
}
// Retrofit Call
Call<JsonObject> call = RetrofitClientLaravel.getInstance(mContext)
.discussGetApi()
.getSomeAction(url);
call.enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(
Call<JsonObject> call,
Response<JsonObject> response) {
JSONObject jsonObject;
try {
jsonObject = new JSONObject(new Gson().toJson(response.body()));
// Get The Relevant Array
JSONObject jsonObject2 = jsonObject.getJSONObject("some_result");
JSONArray returnArray = jsonObject2.getJSONArray("data");
onScrolled();
if (!returnArray.isNull(0)) {
for (int l = 0; l < returnArray.length(); l++) {
if (returnArray.length() > 0) {
// Get The Json Object
JSONObject returnJSONObject = returnArray.getJSONObject(l);
// Get Details
String id = returnJSONObject.optString("SomesomeAction_id");
// Populate The Array List
listSomeActionModel.add(new SomesomeActionListModel(id));
}
}
}
if (firstLoad || firstSearch) {
someActionsAdapter = new SomeActionListAdapter(
mContext,
listSomeActionModel);
rv.setAdapter(someActionsAdapter);
}
someActionsAdapter.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(
Call<JsonObject> call,
Throwable t) {
}
});
}
public void onScrolled() {
rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(
RecyclerView recyclerView,
int newState) {
super.onScrollStateChanged(
recyclerView,
newState);
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
isScrolling = true;
}
}
#Override
public void onScrolled(
RecyclerView recyclerView,
int dx,
int dy) {
super.onScrolled(
recyclerView,
dx,
dy);
currentItems = manager.getChildCount();
totalItems = manager.getItemCount();
scrollOutItems = manager.findFirstVisibleItemPosition();
if (isScrolling && (currentItems + scrollOutItems == totalItems)) {
isScrolling = false;
firstLoad = false;
firstSearch = false;
Toast.makeText(
mContext,
"Loading More...",
Toast.LENGTH_SHORT)
.show();
pageNumber++;
getSomeAction(Env.LARAVEL_MAIN_URL +
"/api/get_SomesomeActions" +
"?page=" +
pageNumber);
}
}
});
}
}
Related
Background:
I am implementing pagination logic with RecyclerView by adding addOnScrollListener function. I'm using the MVVM pattern (https://developer.android.com/jetpack/docs/guide). I aim to display movies resulting from an API call to TheMovieDB in GridLayout, with GridLayoutManager.
Problem faced:
The scroll method is always or never called:
1) I do NOT even need to scroll for it to be triggered.
2) It triggers when I start the app, but when I scroll it doesn't trigger at all
Here is my code
public void getMoviesLL(String categoria, int pagina, MutableLiveData < Resource < List < Movie >>> moviesData) {
Service apiService = Client.getClient().create(Service.class);
Call < MoviesResponse > call;
Log.d(TAG, "CHIAMATA " + pagina);
call = apiService.getTMDB(categoria, Constants.API_KEY, Constants.LINGUA, pagina);
call.enqueue(new Callback < MoviesResponse > () {
#Override
public void onResponse(#NonNull Call < MoviesResponse > call, #NonNull Response < MoviesResponse > response) {
if (response.isSuccessful() && response.body() != null) {
Resource < List < Movie >> resource = new Resource < >();
if (moviesData.getValue() != null && moviesData.getValue().getData() != null) {
List < Movie > currentMovieList = moviesData.getValue().getData();
currentMovieList.remove(currentMovieList.size() - 1);
currentMovieList.addAll(response.body().getResults());
resource.setData(currentMovieList);
} else {
resource.setData(response.body().getResults());
}
resource.setTotalResults(response.body().getTotalResults());
resource.setStatusCode(response.code());
resource.setStatusMessage(response.message());
resource.setLoading(false);
Log.d(TAG, "LOADING FALSE");
moviesData.postValue(resource);
} else if (response.errorBody() != null) {
Resource < List < Movie >> resource = new Resource < >();
resource.setStatusCode(response.code());
try {
resource.setStatusMessage(response.errorBody().string() + "- " + response.message());
} catch(IOException e) {
e.printStackTrace();
}
moviesData.postValue(resource);
}
}
#Override
public void onFailure(#NonNull Call < MoviesResponse > call, #NonNull Throwable t) {
Resource < List < Movie >> resource = new Resource < >();
resource.setStatusMessage(t.getMessage());
moviesData.postValue(resource);
}
});
}
Here is the model
public class Resource<T> {
private T data;
private int totalResults;
private int statusCode;
private String statusMessage;
private boolean isLoading;
public Resource() {}
public Resource(T data, int totalResults, int statusCode, String statusMessage, boolean isLoading) {
this.data = data;
this.totalResults = totalResults;
this.statusCode = statusCode;
this.statusMessage = statusMessage;
this.isLoading = isLoading;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public int getTotalResults() {
return totalResults;
}
public void setTotalResults(int totalResults) {
this.totalResults = totalResults;
}
public int getStatusCode() {
return statusCode;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
public String getStatusMessage() {
return statusMessage;
}
public void setStatusMessage(String statusMessage) {
this.statusMessage = statusMessage;
}
public boolean isLoading() {
return isLoading;
}
public void setLoading(boolean loading) {
isLoading = loading;
}
#Override
public String toString() {
return "Resource{" +
"data=" + data +
", totalResults=" + totalResults +
", statusCode=" + statusCode +
", statusMessage='" + statusMessage + '\'' +
", isLoading=" + isLoading +
'}';
}
}
view model class
public class NuoviArriviViewModel extends ViewModel {
private static final String TAG = "NuoviArriviViewModel";
private MutableLiveData<Resource<List<Movie>>> film;
int page = 1;
private int currentResults;
private boolean isLoading = false;
public MutableLiveData<Resource<List<Movie>>> getProssimeUscite() {
if(film == null) {
film = new MutableLiveData<>();
MoviesRepository.getInstance().getMoviesLL("now_playing", page, film);
}
return film;
}
public MutableLiveData<Resource<List<Movie>>> getMoreProssimeUscite() {
MoviesRepository.getInstance().getMoviesLL("now_playing", page, film);
return film;
}
public MutableLiveData<Resource<List<Movie>>> getMoviesLiveData() {
return film;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getCurrentResults() {
return currentResults;
}
public void setCurrentResults(int currentResults) {
this.currentResults = currentResults;
}
public boolean isLoading() {
return isLoading;
}
public void setLoading(boolean loading) {
isLoading = loading;
}
}
OnScroll Listener
prossimeUsciteRV.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
Log.d(TAG, "entro in onScrolled");
totalItemCount = layoutManager.getItemCount();
lastVisibleItem = layoutManager.findLastVisibleItemPosition();
visibleItemCount = layoutManager.getChildCount();
// Condition to enable the loading of other news while the user scrolls the list
if (totalItemCount == visibleItemCount || (totalItemCount <= (lastVisibleItem + threshold) && dy > 0 && !nuoviArriviViewModel.isLoading()) && nuoviArriviViewModel.getMoviesLiveData().getValue() != null && nuoviArriviViewModel.getCurrentResults() != nuoviArriviViewModel.getMoviesLiveData().getValue().getTotalResults()) {
Resource < List < Movie >> movieListResource = new Resource < >();
MutableLiveData < Resource < List < Movie >>> movieListMutableLiveData = nuoviArriviViewModel.getMoviesLiveData();
if (movieListMutableLiveData.getValue() != null) {
nuoviArriviViewModel.setLoading(true);
List < Movie > currentMovieList = movieListMutableLiveData.getValue().getData();
// It adds a null element to enable the visualization of the loading item (it is managed by the class nuoviArriviAdapter)
currentMovieList.add(null);
movieListResource.setData(currentMovieList);
movieListResource.setStatusMessage(movieListMutableLiveData.getValue().getStatusMessage());
movieListResource.setTotalResults(movieListMutableLiveData.getValue().getTotalResults());
movieListResource.setStatusCode(movieListMutableLiveData.getValue().getStatusCode());
movieListResource.setLoading(true);
movieListMutableLiveData.postValue(movieListResource);
int page = nuoviArriviViewModel.getPage() + 1;
nuoviArriviViewModel.setPage(page);
nuoviArriviViewModel.loadMore();
}
}
}
});
XML file
<?xml version="1.0" encoding="utf-8"?>
<GridLayout
android:layout_width="match_parent"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/nuovi_arrivi_fragment"
android:layout_height="match_parent"
android:background="#color/colorPrimary"
android:orientation="vertical"
tools:context=".ui.nuovi_arrivi.NuoviArriviFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view_nuovi_arrivi"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical" />
</GridLayout>
The problem was that I wrapped my layout in a NestedScrollView, so the onScrolled event couldn't be triggered properly
I have used rxjava and retrofit to load data from backend and update the UI.
But there is no data displayed on section view. I have tested it, and the backend data load successful and the UI can be updated using fake data.
Are there something wrong when I use Rxjava?
private void retrieveCardInfo(String stripeId, String userToken) {
subscriptions.add(NetworkUtil.getRetrofit(userToken).getCustomerInfo(new GetCustomer(stripeId))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::handleCustomerResponse, this::handleError));
}
private void handleCustomerResponse(CreateStripeCustomerResponse response) {
if (response.getSuccess()) {
updateCardList(response);
bankSection.setState(Section.State.EMPTY);
} else {
Utils.toast(this,"Get credit card failed");
}
}
private void updateCardList(CreateStripeCustomerResponse response) {
List<CardInfo> cardList = response.getCustomer().getSources().getData();
if (cardList == null || cardList.size() == 0) {
cardSection.setState(Section.State.EMPTY);
} else {
list = new ArrayList<>();
for (int i = 0; i < cardList.size(); i++) {
CardInfo cardInfo = cardList.get(i);
String brand = cardInfo.getBrand();
String subTitle = cardInfo.getFunding() + "****" + cardInfo.getLast4();
list.add(new PaymentAccountItem(brand, subTitle, cardDrawable.get(brand)));
}
list.add(new PaymentAccountItem("title", "subtitle", R.drawable.ic__credit_amex_svg));
cardSection.swipeData(list);
}
}
private void handleError(Throwable throwable) {
}
// works fine without sectionedAdapter.notifyDataSetChanged(); when using fake data,
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_payment);
ButterKnife.bind(this);
subscriptions = new CompositeSubscription();
initialToolbar();
initialRecyclerView();
initialPaymentData();
}
private void initialPaymentData() {
stripeIdAndToken = Utils.getStripeIdAndToken(this);
if (TextUtils.isEmpty(stripeIdAndToken.first)) {
cardSection.setState(Section.State.EMPTY);
bankSection.setState(Section.State.EMPTY);
} else {
initialCardDrawableResource();
retrieveCardInfo(stripeIdAndToken.first, stripeIdAndToken.second);
}
// fake data here
// initialCardDrawableResource();
// list = new ArrayList<>();
// list.add(new PaymentCreditCardItem("Visa", "123456", 10, 2018, cardDrawable.get("Visa")));
// cardSection.swipeData(list);
}
private void initialCardDrawableResource() {
cardDrawable = new HashMap<>();
cardDrawable.put("Visa", R.drawable.ic_visa_svg);
cardDrawable.put("Discover", R.drawable.ic_discover_svg);
cardDrawable.put("American Express", R.drawable.ic__credit_amex_svg);
cardDrawable.put("Mastercard", R.drawable.cio_ic_mastercard);
}
private void retrieveCardInfo(String stripeId, String token) {
subscriptions.add(NetworkUtil.getRetrofit(token).getCustomerInfo(new GetCustomer(stripeId))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::handleCustomerResponse, this::handleError));
}
private void handleCustomerResponse(CreateStripeCustomerResponse response) {
if (response.getSuccess()) {
updateCardList(response);
} else {
Utils.toast(this, "Get credit card failed");
}
}
private void updateCardList(CreateStripeCustomerResponse response) {
List<CardInfo> cardList = response.getCustomer().getSources().getData();
if (cardList == null || cardList.size() == 0) {
cardSection.setState(Section.State.EMPTY);
} else {
list = new ArrayList<>();
for (int i = 0; i < cardList.size(); i++) {
CardInfo cardInfo = cardList.get(i);
String brand = cardInfo.getBrand();
String cardNum = cardInfo.getFunding() + "****" + cardInfo.getLast4();
list.add(new PaymentCreditCardItem(brand, cardNum, cardInfo.getExpMonth(), cardInfo.getExpYear(), cardDrawable.get(brand)));
}
cardSection.swipeData(list);
sectionedAdapter.notifyDataSetChanged();
}
}
private void handleError(Throwable throwable) {
}
private void initialRecyclerView() {
sectionedAdapter = new SectionedRecyclerViewAdapter();
cardSection = new PaymentCardAndAccountSection(this, R.layout.header_card, R.layout.payment_card_empty_view);
bankSection = new PaymentCardAndAccountSection(this, R.layout.header_bank, R.layout.payment_account_empty_view);
sectionedAdapter.addSection(cardSection);
sectionedAdapter.addSection(bankSection);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(sectionedAdapter);
bankSection.setState(Section.State.EMPTY);
}
private void initialToolbar() {
toolbar.setTitle("Payment");
toolbar.setNavigationIcon(R.drawable.ic_back_svg);
setSupportActionBar(toolbar);
}
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
#OnClick(R.id.fab_add_payment)
void launchAddPaymentDialog() {
AddPaymentDialogFragment addPaymentDialogFragment = AddPaymentDialogFragment.newInstance();
addPaymentDialogFragment.setStyle(DialogFragment.STYLE_NO_FRAME, 0);
addPaymentDialogFragment.show(getSupportFragmentManager(), "dialog");
}
#Override
public void onPause() {
super.onPause();
if (subscriptions != null) {
subscriptions.clear();
}
}
Do you use an adapter? In this case adapter.notifyDataSetChanged();
Also, print yout error: throwable.printStackTrace(); in order to see if something goes wrong.
You need to add .observeOn(AndroidSchedulers.mainThread()) after you write subsribeOn() to tell your observable to perform your onNext callback on UI thread/MainThread.
I am trying to implement pagination in recyclerview to load more chat messages when the user scrolls to top , this is achieved by sending the last message time i.e coversations[0] time to the API , but when the new list is added the old List gets repeated many times . I think this is because i am not updating the time properly , What is the correct way to achieve this?
This is the code i am using, first time i am setting the flag to false and time as empty.
getConvoData(k, " ", "", false);
private String last_msg_time = " ";
private Boolean flag = false;
rv_convo.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (!recyclerView.canScrollVertically(-1)) {
if (conversations != null) {
String time = last_msg_time;
getConvoData(k, " ", time, true);
}
}
}
});
this is the method for fetching conversation Data
private void getConvoData(final String k, final String new_message, final String last_time, final boolean flag) {
final String token1 = Global.shared().tb_token;
final String url = "https://app.aer.media/v2/message_router/_getChat";
final JSONObject jsonBody = new JSONObject();
final ProgressDialog progressDialog = new ProgressDialog(this);
final String mRequestBody = jsonBody.toString();
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new com.android.volley.Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jObj = new JSONObject(response);
final JSONObject data = jObj.getJSONObject("data");
conversations = data.getJSONArray("conversation");
JSONObject for_chat = data.getJSONObject("for_chat");
JSONArray jsonArr_chat = new JSONArray();
jsonArr_chat.put(for_chat);
params = (RelativeLayout.LayoutParams) rv_convo.getLayoutParams();
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
if (!flag) {
convobeans = gson.fromJson(conversations.toString(), convType);
last_msg_time = conversations.getJSONObject(0).getString("time");
Log.d("OldList", convobeans.toString());
adapter = new ChatDetailsAdapter(forChatBeen, convobeans, ChatDetailsActivity.this, forChatBeansList, image, name, initials, new_message, bitmap);
// Collections.reverse(convobeans);
rv_convo.setAdapter(adapter);
rv_convo.smoothScrollToPosition( rv_convo.getAdapter().getItemCount() - 1);
adapter.notifyDataSetChanged();
rv_convo.setNestedScrollingEnabled(true);
} else {
newConvo = gson.fromJson(conversations.toString(), convType);
last_msg_time = conversations.getJSONObject(0).getString("time");
if (newConvo != null && newConvo.size() > 0) {
Log.d("newList", newConvo.toString());
convobeans.addAll(0, newConvo);
adapter.notifyItemChanged(0, newConvo.size());
}
}
}
}
}
Depending on the flag I am updating the list and updating the time as well but the list gets repeated in the RecyclerView due to the previous time being passed , how do I update the time optimally and fetch the new list each time?
This code is used to fetch the data when the user scroll down in a recylerview. Just analyze this code you will get the basic idea.
rvCategory.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) {
visibleItemCount = mLinearLayoutManager.getChildCount();
totalItemCount = mLinearLayoutManager.getItemCount();
pastVisiblesItems = mLinearLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if ((visibleItemCount + pastVisiblesItems) >= totalItemCount) {
loading = false;
fetchData();
}
}
}
}
});
Function FetchData()
private void fetchData() {
String url = EndPoints.location + "getMobileData.php?lastData=" + lastData;
JsonObjectRequest jsObjRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
lastData = response.getString("last");
JSONArray jArray = response.getJSONArray("response");
if (jArray.length() == 0) {
//Empty condition
} else {
for (int i = 0; i < jArray.length(); i++) {
//Append the chat with the Dataobject of your modelAnd swap the recylerview view with new data
//Example
}
adapter.swap(rvHomeModel.createHomeList(DataPathsHome, true));
}
} catch (JSONException e) {
e.printStackTrace();
}
loading = true;
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// TODO Auto-generated method stub
loading = true;
Toast.makeText(CategoryView.this, "No internet connection", Toast.LENGTH_LONG).show();
}
});
// Add a request (in this example, called stringRequest) to your RequestQueue.
MySingleton.getInstance(this).addToRequestQueue(jsObjRequest);
}
Create a function called swap in your adapter class that accept the new dataset
public void swap(List<rvHomeModel> list) {
//Check your previouse dataset used in adapter is empty or not
if (rvHomeModels!= null) {
rvHomeModels.clear();
rvHomeModels.addAll(list);
} else {
rvHomeModels = list;
}
notifyDataSetChanged();
}
At server
1. Get the previous value
2. Do the database operation and get the chats id < of previous
2. Create a JSON Object contain
{
last:last_chat_id,
response:{
//Your chat
}
}
This is not a perfect solution for this question. But you will get the basic idea about what you are looking for.
I have a problem with the endless scroll. Every time it loads more data, it returns to the top view. What I want is the RecyclerView to stay in the last position when it loads new data.
I am trying to implement this code https://github.com/codepath/android_guides/wiki/Endless-Scrolling-with-AdapterViews-and-RecyclerView
here is the endless scroll code
public abstract class EndlessRecyclerViewScrollListener extends RecyclerView.OnScrollListener{
// The minimum amount of items to have below your current scroll position
// before loading more.
private int visibleThreshold = 30;
// The current offset index of data you have loaded
private int currentPage = 0;
// The total number of items in the dataset after the last load
private int previousTotalItemCount = 0;
// True if we are still waiting for the last set of data to load.
private boolean loading = true;
// Sets the starting page index
private int startingPageIndex = 0;
RecyclerView.LayoutManager mLayoutManager;
public EndlessRecyclerViewScrollListener(LinearLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
}
public int getLastVisibleItem(int[] lastVisibleItemPositions) {
int maxSize = 0;
for (int i = 0; i < lastVisibleItemPositions.length; i++) {
if (i == 0) {
maxSize = lastVisibleItemPositions[i];
}
else if (lastVisibleItemPositions[i] > maxSize) {
maxSize = lastVisibleItemPositions[i];
}
}
return maxSize;
}
// This happens many times a second during a scroll, so be wary of the code you place here.
// We are given a few useful parameters to help us work out if we need to load some more data,
// but first we check if we are waiting for the previous load to finish.
#Override
public void onScrolled(RecyclerView view, int dx, int dy) {
int lastVisibleItemPosition = 0;
int totalItemCount = mLayoutManager.getItemCount();
if (mLayoutManager instanceof LinearLayoutManager) {
lastVisibleItemPosition = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition();
}
// If the total item count is zero and the previous isn't, assume the
// list is invalidated and should be reset back to initial state
if (totalItemCount < previousTotalItemCount) {
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = totalItemCount;
if (totalItemCount == 0) {
this.loading = true;
}
}
// If it’s still loading, we check to see if the dataset count has
// changed, if so we conclude it has finished loading and update the current page
// number and total item count.
if (loading && (totalItemCount > previousTotalItemCount)) {
loading = false;
previousTotalItemCount = totalItemCount;
}
// If it isn’t currently loading, we check to see if we have breached
// the visibleThreshold and need to reload more data.
// If we do need to reload some more data, we execute onLoadMore to fetch the data.
// threshold should reflect how many total columns there are too
if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount) {
currentPage++;
onLoadMore(currentPage, totalItemCount, view);
loading = true;
}
}
// Call this method whenever performing new searches
public void resetState() {
this.currentPage = this.startingPageIndex;
this.previousTotalItemCount = 0;
this.loading = true;
}
// Defines the process for actually loading more data based on page
public abstract void onLoadMore(int page, int totalItemsCount, RecyclerView view);
}
OnCreateView
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.booking_fragment, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.bookingRecyclerView);
linearLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setHasFixedSize(true);
scrollListener = new EndlessRecyclerViewScrollListener(linearLayoutManager) {
#Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
// Triggered only when new data needs to be appended to the list
// Add whatever code is needed to append new items to the bottom of the list
if(CurrentStatus.equals("notSearch")){
if (current < Integer.parseInt(TP)) {
current++;
loadMoreBookings(sort);
}
else if(current == Integer.parseInt(TP)){
Toast.makeText(getActivity(),"No More Data to Load", Toast.LENGTH_SHORT).show();
}
}else{
if (current < Integer.parseInt(TP)) {
current++;
searchMoreBookings(search, sort);
}
else if(current == Integer.parseInt(TP)){
Toast.makeText(getActivity(),"No More Data to Be Load", Toast.LENGTH_SHORT).show();
}
}
}
LoadMoreBookings
private void loadMoreBookings(final String sort){
CurrentStatus = "notSearch";
final ProgressDialog progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("Please Wait While Retrieving Data");
progressDialog.setCancelable(false);
progressDialog.show();
StringRequest requesting = new StringRequest(Request.Method.POST, URL,
new Response.Listener<String>() {
#Override
public void onResponse(String JSONString) {
progressDialog.dismiss();
try{
JSONObject jsonTP = new JSONObject(JSONString);
JSONArray jsonArrayB = jsonTP.getJSONArray("Data");
for(int i = 0; i < jsonArrayB.length(); i++){
JSONObject o = jsonArrayB.getJSONObject(i);
Booking list = new Booking(
o.getString("bookID"),
o.getString("userEmail"),
o.getString("paymentMethod"),
o.getString("paymentStatus"),
o.getString("totalPrice"),
o.getString(String.valueOf("securityCode")),
o.getString(String.valueOf("travelDate")),
o.getString("paymentID"),
o.getString("userFN"),
o.getString("userLN"),
o.getString(String.valueOf("createdAt")),
o.getString("tTM"),
o.getString("messageToCustomer"),
o.getString("messageFromMerchant"),
o.getString("wCN"),
o.getString("wLocation"),
o.getString("wWebsite")
);
listBooking.add(list);
count++;
}
Toast.makeText(getActivity(), "Data : "+count, Toast.LENGTH_SHORT).show();
adapter = new BookingAdapter(listBooking,getActivity());
recyclerView.setAdapter(adapter);
} catch (JSONException e) {
loadMoreBookings(sort);
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
progressDialog.dismiss();
Toast.makeText(getActivity().getApplicationContext(), "Failed To Retrieve Data. Please Try Again.",Toast.LENGTH_LONG).show();
}
}
){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params = new HashMap<String, String>();
String user = getActivity().getIntent().getStringExtra("username");
params.put("username", user);
params.put("currentpage", String.valueOf(current));
params.put("sorting", sort);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(getActivity().getApplicationContext());
requestQueue.add(requesting);
}
set adapter in onCreateView()
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view = inflater.inflate(R.layout.booking_fragment, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.bookingRecyclerView);
linearLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(linearLayoutManager);
adapter = new BookingAdapter(listBooking,getActivity());
recyclerView.setAdapter(adapter);
scrollListener = new EndlessRecyclerViewScrollListener(linearLayoutManager) {
#Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
// Triggered only when new data needs to be appended to the list
// Add whatever code is needed to append new items to the bottom of the list
if(CurrentStatus.equals("notSearch")){
if (current < Integer.parseInt(TP)) {
current++;
loadMoreBookings(sort);
}
else if(current == Integer.parseInt(TP)){
Toast.makeText(getActivity(),"No More Data to Load", Toast.LENGTH_SHORT).show();
}
}else{
if (current < Integer.parseInt(TP)) {
current++;
searchMoreBookings(search, sort);
}
else if(current == Integer.parseInt(TP)){
Toast.makeText(getActivity(),"No More Data to Be Load", Toast.LENGTH_SHORT).show();
}
}
}
don't set adapter every time just notify the adapter item inserted at position.
private void loadMoreBookings(final String sort){
CurrentStatus = "notSearch";
final ProgressDialog progressDialog = new ProgressDialog(getActivity());
progressDialog.setMessage("Please Wait While Retrieving Data");
progressDialog.setCancelable(false);
progressDialog.show();
StringRequest requesting = new StringRequest(Request.Method.POST, URL,
new Response.Listener<String>() {
#Override
public void onResponse(String JSONString) {
progressDialog.dismiss();
try{
JSONObject jsonTP = new JSONObject(JSONString);
JSONArray jsonArrayB = jsonTP.getJSONArray("Data");
for(int i = 0; i < jsonArrayB.length(); i++){
JSONObject o = jsonArrayB.getJSONObject(i);
Booking list = new Booking(
o.getString("bookID"),
o.getString("userEmail"),
o.getString("paymentMethod"),
o.getString("paymentStatus"),
o.getString("totalPrice"),
o.getString(String.valueOf("securityCode")),
o.getString(String.valueOf("travelDate")),
o.getString("paymentID"),
o.getString("userFN"),
o.getString("userLN"),
o.getString(String.valueOf("createdAt")),
o.getString("tTM"),
o.getString("messageToCustomer"),
o.getString("messageFromMerchant"),
o.getString("wCN"),
o.getString("wLocation"),
o.getString("wWebsite")
);
listBooking.add(list);
adapter.notifyItemInserted(count);
count++;
}
Toast.makeText(getActivity(), "Data : "+count, Toast.LENGTH_SHORT).show();
} catch (JSONException e) {
loadMoreBookings(sort);
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
progressDialog.dismiss();
Toast.makeText(getActivity().getApplicationContext(), "Failed To Retrieve Data. Please Try Again.",Toast.LENGTH_LONG).show();
}
}
){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params = new HashMap<String, String>();
String user = getActivity().getIntent().getStringExtra("username");
params.put("username", user);
params.put("currentpage", String.valueOf(current));
params.put("sorting", sort);
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(getActivity().getApplicationContext());
requestQueue.add(requesting);
}
I have a recycler view in which I load some data from the server when user scroll to bottom I want to show a progress bar and send another request to the server for more data. I have tried below code but it not able to load more data from the server. please help
private RecyclerView mRecyclerView;
private List<User> mUsers = new ArrayList<>();
private UserAdapter mUserAdapter;
private static String sz_RecordCount;
private static String sz_LastCount;
private final int m_n_DefaultRecordCount = m_kDEFAULT_RECORD_COUNT;
private static final int m_kDEFAULT_RECORD_COUNT = 5;
private ArrayList<CDealAppDatastorage> s_oDataset;
private String TAG = MainActivity.class.getSimpleName();
private CDealAppDatastorage item;
private static int arrayCount;
private Context context;
private PreferenceHelper m_oPreferenceHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = MainActivity.this;
m_oPreferenceHelper = new PreferenceHelper(context);
sz_RecordCount = String.valueOf(m_n_DefaultRecordCount);// increment of record count
int intialLastCount = 0;
sz_LastCount = String.valueOf(intialLastCount);// increment of last count...
s_oDataset = new ArrayList<>();// making object of Arraylist
//initial request for data
initalDealListing();
mRecyclerView = (RecyclerView) findViewById(R.id.recycleView);
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());
//sending request to server for more data
moreDealsRequest();
mUserAdapter.notifyDataSetChanged();
mUserAdapter.setLoaded();
}
}, 5000);
}
});
}
private void initalDealListing() {
String m = "9565656565";
String p = "D55A8077E0208A5C5B25176608EF84BD";
// 3. build jsonObject
try {
final JSONObject jsonObject = new JSONObject();// making object of Jsons.
jsonObject.put("agentCode", m.trim());// put mobile number
jsonObject.put("pin", p.trim());// put password
jsonObject.put("recordcount", sz_RecordCount.trim());// put record count
jsonObject.put("lastcountvalue", sz_LastCount.trim());// put last count
Log.e("CAppList:", sz_RecordCount);
Log.e("Capplist:", sz_LastCount);
Log.d(TAG, "Server Request:-" + jsonObject.toString());
final String m_DealListingURL = APIStorage.IREWARDS_URL + APIStorage.DEALLISTING_URL;
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, m_DealListingURL, jsonObject, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.d(TAG, "Server Response:-" + response);
try {
int nResultCodeFromServer = Integer.parseInt(response.getString(ServerResponseStorage.s_szRESULT_CODE));
if (nResultCodeFromServer == ConstantInt.m_kTRANSACTION_SUCCESS) {
JSONArray posts = response.optJSONArray(ServerResponseStorage.s_szDEAL_ARRAY);// get Deal list in array from response
s_oDataset.clear();
for (int i = 0; i < posts.length(); i++) {// loop for counting deals from server
try {
JSONObject post = posts.getJSONObject(i);// counting deal based on index
item = new CDealAppDatastorage();// creating object of DealAppdata storage
item.setM_szHeaderText(post.getString(ServerResponseStorage.s_szDEAL_NAME));// get deal name from response
item.setM_szsubHeaderText(post.getString(ServerResponseStorage.s_szDEAL_CODE));// get dealcode from response
s_oDataset.add(item);// add all items in ArrayList
} catch (Exception e) {
e.printStackTrace();
}
}
arrayCount = posts.length();
Log.d(TAG, "ArrayCount::" + arrayCount);
/*here we are storing no. of deals coming from server*/
// write
m_oPreferenceHelper.saveIntegerValue("LastCountLength", arrayCount);
if (!s_oDataset.isEmpty()) {// condition if data in arraylist is not empty
mRecyclerView.setAdapter(mUserAdapter);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "Server error:-" + error);
}
});
RequestQueue requestQueue = Volley.newRequestQueue(context);
jsonObjectRequest.setRetryPolicy(new DefaultRetryPolicy(ConstantInt.INITIAL_TIMEOUT_MS, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(jsonObjectRequest);
} catch (JSONException e) {
e.printStackTrace();
}
}
/*This method send request to server for more deals*/
private void moreDealsRequest() {
try {
// 3. build jsonObject
final JSONObject jsonObject = new JSONObject();// making object of Jsons.
jsonObject.put(ServerRequestKeyStorage.s_szAGENT_CODE, "9565656565");// put mobile number
jsonObject.put(ServerRequestKeyStorage.s_szPASSWORD, "D55A8077E0208A5C5B25176608EF84BD");// put password
jsonObject.put(ServerRequestKeyStorage.s_szRECORD_COUNT, sz_RecordCount.trim());// put record count
jsonObject.put(ServerRequestKeyStorage.s_szLAST_COUNT, sz_LastCount.trim());// put last count
Log.e("CAppList:", sz_RecordCount);
Log.e("Capplist:", sz_LastCount);
// 4. convert JSONObject to JSON to String
Log.e(TAG, "Server Request:-" + jsonObject.toString());
RequestQueue requestQueue = Volley.newRequestQueue(context);
final String imgPath = APIStorage.IREWARDS_URL + APIStorage.DEAL_IMAGE_PATH;
final String m_DealListingURL = APIStorage.IREWARDS_URL + APIStorage.DEALLISTING_URL;
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, m_DealListingURL, jsonObject, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.e(TAG, "Server Response:-" + response);
try {
int nResultCodeFromServer = Integer.parseInt(response.getString(ServerResponseStorage.s_szRESULT_CODE));
if (nResultCodeFromServer == ConstantInt.m_kTRANSACTION_SUCCESS) {
// Select the last row so it will scroll into view...
JSONArray posts = response.optJSONArray(ServerResponseStorage.s_szDEAL_ARRAY);// GETTING DEAL LIST
for (int i = 0; i < posts.length(); i++) {
try {
JSONObject post = posts.getJSONObject(i);// GETTING DEAL AT POSITION AT I
item = new CDealAppDatastorage();// object create of DealAppdatastorage
item.setM_szHeaderText(post.getString(ServerResponseStorage.s_szDEAL_NAME));//getting deal name
item.setM_szsubHeaderText(post.getString(ServerResponseStorage.s_szDEAL_CODE));// getting deal code
s_oDataset.add(item);
} catch (Exception e) {
e.printStackTrace();
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "Server Error::" + error);
}
});
jsonObjectRequest.setRetryPolicy(new DefaultRetryPolicy(ConstantInt.INITIAL_TIMEOUT_MS, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
requestQueue.add(jsonObjectRequest);
} catch (JSONException e) {
e.printStackTrace();
}
}
static class UserViewHolder extends RecyclerView.ViewHolder {
public TextView tvName;
public TextView tvEmailId;
public UserViewHolder(View itemView) {
super(itemView);
tvName = (TextView) itemView.findViewById(R.id.tvName);
tvEmailId = (TextView) itemView.findViewById(R.id.tvEmailId);
}
}
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 s_oDataset.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.layout_user_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) {
CDealAppDatastorage user = s_oDataset.get(position);
UserViewHolder userViewHolder = (UserViewHolder) holder;
userViewHolder.tvName.setText(user.getM_szHeaderText());
userViewHolder.tvEmailId.setText(user.getM_szsubHeaderText());
} else if (holder instanceof LoadingViewHolder) {
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
loadingViewHolder.progressBar.setIndeterminate(true);
}
}
#Override
public int getItemCount() {
return s_oDataset == null ? 0 : s_oDataset.size();
}
public void setLoaded() {
isLoading = false;
}
}
}
Use Below Code:
First Declare these global variables:
int visibleItemCount, totalItemCount = 1;
int firstVisiblesItems = 0;
int totalPages = 1; // get your total pages from web service first response
int current_page = 0;
boolean canLoadMoreData = true; // make this variable false while your web service call is going on.
LinearLayoutManager linearLayoutManager;
Assign Layout manager to your Recyclerview:
linearLayoutManager = new LinearLayoutManager(mActivity);
mRecyclerView.setLayoutManager(linearLayoutManager);
Scroll Listener of your recyclerview:
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (dy > 0) //check for scroll down
{
visibleItemCount = linearLayoutManager.getChildCount();
totalItemCount = linearLayoutManager.getItemCount();
firstVisiblesItems = linearLayoutManager.findFirstVisibleItemPosition();
if (canLoadMoreData) {
if ((visibleItemCount + firstVisiblesItems) >= totalItemCount) {
if (current_page < totalPages) {
canLoadMoreData = false;
/**
* .
* .
* .
* .call your webservice with page index
* .
* .
*
*/
//After completion of web service make 'canLoadMoreData = true'
}
}
}
}
}
});
Too late but i'm also refer same way check with my code it work for me
Here is API call using retrofit and get listnotifications then in this method i create one more method for loadmore getMoreNotificationListApiCall()
public void getNotification()
{
if (listnotifications.size() > 0) {
notificationListAdapter = new NotificationListAdapter(NotificationListActivity.this, listnotifications, notificationListRecyclerview);
notificationListRecyclerview.setAdapter(notificationListAdapter);
notificationListAdapter.setOnLoadMoreListener(new OnLoadMoreListener() {
#Override
public void onLoadMore() {
Log.e("ad", "Load More");
listnotifications.add(null);
Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
if (listnotifications.size()>0) {
notificationListAdapter.notifyItemInserted(listnotifications.size() - 1);
}
}
};
handler.post(r);
try {
if (CommonUtils.isConnectingToInternet(NotificationListActivity.this)) {
// Internet Connection is Present
getMoreNotificationListApiCall();
} else {
//Remove loading item
if (listnotifications.size()>0) {
listnotifications.remove(listnotifications.size() - 1);
}
notificationListAdapter.notifyItemRemoved(listnotifications.size());
CommonUtils.commonToast(NotificationListActivity.this, getResources().getString(R.string.no_internet_exist));
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
getMoreNotificationListApiCall() method code in this method i increment startlimit means page index and remove null (i'm using retorfit for api call)
private void getMoreNotificationListApiCall() {
try {
if (CommonUtils.isConnectingToInternet(NotificationListActivity.this)) {
StartLimit = StartLimit + 10;
Call<NotificationBase> call = ApiHandler.getApiService().getNotificationListApi(notificationListJsonMap());
call.enqueue(new Callback<NotificationBase>() {
#Override
public void onResponse(Call<NotificationBase> registerCall, Response<NotificationBase> response) {
Log.e(TAG, " Full json gson => " + "Hi i am here");
try {
Log.e(TAG, " Full json gson => " + new Gson().toJson(response));
JSONObject jsonObj = new JSONObject(new Gson().toJson(response).toString());
Log.e(TAG, " responce => " + jsonObj.getJSONObject("body").toString());
if (response.isSuccessful()) {
int success = response.body().getSuccess();
if (success == 1) {
List<NotificationBean> moreNotication = response.body().getNotificatons();
//Remove loading item
if (listnotifications.size() > 0) {
listnotifications.remove(listnotifications.size() - 1);
}
notificationListAdapter.notifyItemRemoved(listnotifications.size());
for (int i = 0; i < moreNotication.size(); i++) {
listnotifications.add(moreNotication.get(i));
}
notificationListAdapter.notifyDataSetChanged();
notificationListAdapter.setLoaded();
} else if (success == 0) {
if (listnotifications.size() > 0) {
listnotifications.remove(listnotifications.size() - 1);
}
notificationListAdapter.notifyItemRemoved(listnotifications.size());
} else {
if (listnotifications.size() > 0) {
listnotifications.remove(listnotifications.size() - 1);
}
notificationListAdapter.notifyItemRemoved(listnotifications.size());
}
} else {
if (listnotifications.size() > 0) {
listnotifications.remove(listnotifications.size() - 1);
}
notificationListAdapter.notifyItemRemoved(listnotifications.size());
}
} catch (Exception e) {
e.printStackTrace();
try {
Log.e(TAG, "error=" + e.toString());
if (listnotifications.size() > 0) {
listnotifications.remove(listnotifications.size() - 1);
}
notificationListAdapter.notifyItemRemoved(listnotifications.size());
} catch (Resources.NotFoundException e1) {
e1.printStackTrace();
}
}
}
#Override
public void onFailure(Call<NotificationBase> call, Throwable t) {
try {
Log.e(TAG, "error" + t.toString());
if (listnotifications.size() > 0) {
listnotifications.remove(listnotifications.size() - 1);
}
notificationListAdapter.notifyItemRemoved(listnotifications.size());
} catch (Resources.NotFoundException e) {
e.printStackTrace();
}
}
});
} else {
CommonUtils.commonToast(NotificationListActivity.this, getResources().getString(R.string.no_internet_exist));
}
} catch (Resources.NotFoundException e) {
e.printStackTrace();
}
}
Here is my Adapter class in which i implement OnLoadMoreListener
public class NotificationListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static List<NotificationBean> mList;
private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_LOADING = 1;
FragmentActivity mFragmentActivity;
private OnLoadMoreListener mOnLoadMoreListener;
private boolean isLoading;
private int visibleThreshold = 5;
private int lastVisibleItem, totalItemCount;
public NotificationListAdapter(FragmentActivity fragmentActivity, List<NotificationBean> data, RecyclerView mRecyclerView) {
this.mList = data;
this.mFragmentActivity = fragmentActivity;
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 mList.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
}
public void delete(int position) { //removes the row
Log.e("Position : ", "" + position);
mList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mList.size());
}
// Return the size arraylist
#Override
public int getItemCount() {
return mList == null ? 0 : mList.size();
}
public void setLoaded() {
isLoading = false;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
// create a new view
View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item_notification_list, parent, false);
return new ViewHolder(itemLayoutView);
} else if (viewType == VIEW_TYPE_LOADING) {
View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(
R.layout.loading_layout, parent, false);
return new LoadingViewHolder(itemLayoutView);
}
return null;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof ViewHolder) {
try {
final ViewHolder viewHolder = (ViewHolder) holder;
viewHolder.singleBean = mList.get(position);
viewHolder.pos = position;
final NotificationBean list = mList.get(position);
String notificationTitle = list.getMessage();
String notificationTimeDate = list.getCreatedDatetime();
String notificationIsRead = list.getIsRead();
} catch (Exception e) {
e.printStackTrace();
}
} else if (holder instanceof LoadingViewHolder) {
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
loadingViewHolder.progressBar.setIndeterminate(true);
}
}
static class LoadingViewHolder extends RecyclerView.ViewHolder {
public ProgressBar progressBar;
public LoadingViewHolder(View itemView) {
super(itemView);
progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar1);
}
}
public class ViewHolder extends RecyclerView.ViewHolder {
public NotificationBean singleBean;
int pos;
TextView txt_notification_time_date;
CustomTextview checkbox_notification;
RelativeLayout rl_row_background;
public ViewHolder(final View v) {
super(v);
checkbox_notification = (CustomTextview) v.findViewById(R.id.checkbox_notification);
//checkbox_notification.setButtonDrawable(android.R.color.transparent);//custom_checkbox
// txt_notification_title= (TextView) v.findViewById(R.id.txt_notification_title);
txt_notification_time_date = (TextView) v.findViewById(R.id.txt_notification_time_date);
rl_row_background = (RelativeLayout) v.findViewById(R.id.rl_row_background);
}
}
public void refreshAdapter() {
notifyDataSetChanged();
}
}
here is xml file 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"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:orientation="vertical">
<ProgressBar
android:id="#+id/progressBar1"
style="#style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:indeterminate="true" />
</LinearLayout>
Fetching the data from server is a Async Task. So you need to enclose the
updation code in a runOnUiThread runnable. to change UI.
runOnUiThread(new Runnable() {
#Override
public void run() {
mUsers.remove(mUsers.size() - 1);
mUserAdapter.notifyItemRemoved(mUsers.size());
//sending request to server for more data
moreDealsRequest();
mUserAdapter.notifyDataSetChanged();
mUserAdapter.setLoaded();
}});