How to use pagination with combined OR queries in firebase - java

I have followed this tutorial on how to achieve pagination with Firestore, however I need to use it with combined queries so I customized my code to look like this:
//combining queries
ArrayList<Task> tasks = new ArrayList<>();
for (String user : following) {
Task t = postRef.whereEqualTo("publisher", user).orderBy("Date", Query.Direction.DESCENDING).limit(1).get();
tasks.add(t);
}
//getting the result from combined queries - works fine
Task<List<QuerySnapshot>> allTasks = Tasks.whenAllSuccess(tasks);
allTasks.addOnSuccessListener(new OnSuccessListener<List<QuerySnapshot>>() {
#Override
public void onSuccess(List<QuerySnapshot> querySnapshots) {
for (QuerySnapshot queryDocumentSnapshots : querySnapshots) {
for (QueryDocumentSnapshot document : queryDocumentSnapshots) {
PostModel post = document.toObject(PostModel.class);
PostsDataHolder.add(post);
}
progressBar.setVisibility(View.GONE);
recyclerView.setVisibility(VISIBLE);
if (queryDocumentSnapshots.size()>0)lastVisible = queryDocumentSnapshots.getDocuments().get(queryDocumentSnapshots.size() - 1);
}
buildRecyclerView();
Toast.makeText(getActivity() , PostsDataHolder.size()+"", Toast.LENGTH_SHORT).show();
RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
isScrolling = true;
}
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int firstVisibileItem = linearLayoutManager.findFirstVisibleItemPosition();
int visibleItemCount = linearLayoutManager.getChildCount();
int totalItemCount = linearLayoutManager.getItemCount();
if (isScrolling && (firstVisibileItem + visibleItemCount == totalItemCount) && !isLastItemPaged) {
isScrolling = false;
// getting the next queries
ArrayList<Task> nextTasks = new ArrayList<>();
for (String user : following) {
Task t = postRef.whereEqualTo("publisher", user).orderBy("Date").startAfter(lastVisible).limit(1).get();
nextTasks.add(t);
}
//getting the next results - doesn't work i just get the same results as the first query
Task<List<QuerySnapshot>> nextAllTasks = Tasks.whenAllSuccess(tasks);
nextAllTasks.addOnSuccessListener(new OnSuccessListener<List<QuerySnapshot>>() {
#Override
public void onSuccess(List<QuerySnapshot> querySnapshots) {
for (QuerySnapshot nextQueryDocumentSnapshots : querySnapshots)
{
for (QueryDocumentSnapshot document : nextQueryDocumentSnapshots) {
PostModel post = document.toObject(PostModel.class);
PostsDataHolder.add(post);
}
adapter.notifyDataSetChanged();
if (nextQueryDocumentSnapshots.size() < 1) isLastItemPaged = true;
if (nextQueryDocumentSnapshots.size() > 0)
lastVisible = nextQueryDocumentSnapshots.getDocuments().get(nextQueryDocumentSnapshots.size() - 1);
}
}
});
}
}
};
recyclerView.addOnScrollListener(onScrollListener);
}
});
But the posts are just duplicating instead of getting new ones, I have read somewhere in the documentation about continueWith() but I don't seem to understand how it works, is that what I'm missing in my code?

It's not possible to exclude documents from a query. To that point, if you if you are performing multiple queries (for any reason), it's not possible to have them return only unique documents among those queries.
To put it another way: each query will always return all of the matching document, regardless of any other conditions you might like to impose. You will have to remove any duplicate documents from your result sets in the code that performs the queries. There is no alternative or workaround for this.

Related

Sorting or filtering Recyclerview with Chips in Android

What is the best way to implement a filtering ChipGroup on a recyclerview?
I have an EditText that user can put a value for filtering, after press Enter key a chip is added on the ChipGroup. How I can filter all the users put to the group?
Code
//txtBuscarULD is an Edittext field
public void onTextChanged(CharSequence s, int i, int i1, int i2) {
if(txtBuscarULD.getText().length()>0){
if (s.length()>0 && s.subSequence(s.length()-1, s.length()).toString().equalsIgnoreCase("\n")) {
chip = new Chip(PlanchasActivity.this);
chip.setText(txtBuscarULD.getText().toString().replace("\n",""));
chip.setCloseIconVisible(true);
chip.setCheckable(true);
chip.setChecked(true);
chip.setOnCloseIconClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
grupoChip.removeView(view);
}
});
grupoChip.addView(chip);
txtBuscarULD.setText("");
filterChips();
}
}
private void filterChips() {
ArrayList<ItemULD> arrayFiltrada = new ArrayList<>();
List<Integer> ids = grupoChip.getCheckedChipIds();
List<String> lista = new ArrayList<>();
for (Integer id:ids){
Chip chip = grupoChip.findViewById(id);
lista.add(chip.getText().toString());
}
for (ItemULD uld : arrayULD) {
for (String str : lista) {
if (uld.getContorno().toUpperCase().contains(str.toUpperCase())
|| uld.getNumULD().toUpperCase().contains(str.toUpperCase())) {
arrayFiltrada.add(uld);
}
}
}
adapter.filterList(arrayFiltrada);
recyclerULD.setAdapter(adapter);
}
This is not working as I expect, (image) (ignore "Red"):
[]
This repeat the "EK" item cause it has the 2 conditions.
And the item "AF" should not appear cause is not like "EK"

google places api: placesClient.findAutocompletePredictions returns task unsuccessful

i used placesClient.findAutocompletePredictions to return location suggestions to set them my search bar, but when i use this functions below, task is always insuccessul why is that, is it from the api key but i enabled places api!!. Result always "prediction fetching task unsuccessful"
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
AutocompleteSessionToken token = AutocompleteSessionToken.newInstance();
FindAutocompletePredictionsRequest predictionsRequest = FindAutocompletePredictionsRequest.builder()
.setCountry("sa")
.setTypeFilter(TypeFilter.ADDRESS)
.setSessionToken(token)
.setQuery(s.toString())
.build();
placesClient.findAutocompletePredictions(predictionsRequest).addOnCompleteListener(new OnCompleteListener<FindAutocompletePredictionsResponse>() {
#Override
public void onComplete(#NonNull Task<FindAutocompletePredictionsResponse> task) {
if (task.isSuccessful()) {
FindAutocompletePredictionsResponse predictionsResponse = task.getResult();
if (predictionsResponse != null) {
predictionList = predictionsResponse.getAutocompletePredictions();
List<String> suggestionsList = new ArrayList<>();
for (int i = 0; i < predictionList.size(); i++) {
AutocompletePrediction prediction = predictionList.get(i);
suggestionsList.add(prediction.getFullText(null).toString());
}
materialSearchBar.updateLastSuggestions(suggestionsList);
if (!materialSearchBar.isSuggestionsVisible()) {
materialSearchBar.showSuggestionsList();
}
}
} else {
Log.i("mytag", "prediction fetching task unsuccessful");
}
}
});
}

How can i prevent recyclerview scrolling to start when i load more data

I am trying to build a news feed using cardviews listed in a recyclerview. Problem is, when I load more data by scrolling, it is automatically scrolling to top of page. I want to know how I can prevent this.
I have overrided the onScrolled method of Recyclerview's onScrollListener to load more data. I am adding new data to an Arraylist every time with my fetchingJSON() function. Then I am calling setupRecycler() function to setup Recyclerview with my updated Arraylist.
So let's say that I loaded 4 news at beginning, then I scrolled to bottom of page and loaded 4 more news. Its just adding new data to Arraylist and kind of re-creating recyclerview. I think that's why there's not much difference in installing 8 news at first.But I don't know what to do to avoid that.
/*Here I am controlling if user has reached to bottom of page, and calling fetchingJSON() function.*/
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visibleItemCount = lManager.getChildCount();
int totalItemCount = lManager.getItemCount();
int firstVisibleItemPosition = lManager.findFirstVisibleItemPosition();
if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount
&& firstVisibleItemPosition >= 0
&& totalItemCount >= PAGE_SIZE && !isLoading) {
newsFeed.this.postPage++;
fetchingJSON();
}
}
});
Then in fetchingJSON() function, i am calling parseJSONData function to parse response.
I'm not doing this in onResponse because volley's asynchronous operation causes some problems
private void fetchingJSON() {
isLoading = true;
String url = getResources().getString(R.string.haberUrl);
StringRequest jsonStringRequest = new StringRequest(
Request.Method.POST, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
parseJSONData(response);
}
},
new Response.ErrorListener() {
#Override
.
.
.
In parseJSONData function ; I am getting the data from JSON response, setting my object's attributes with that. Than adding my object to Arraylist. Finally I am calling setupRecycler function to re-create my Recyclerview with updated data .
public void parseJSONData(String response) {
try {
JSONObject obj = new JSONObject(response);
JSONArray dataArray = obj.getJSONArray("data");
for (int i = 0; i < dataArray.length(); i++) {
JSONObject dataobj = dataArray.getJSONObject(i);
haberModel1.setTitle(dataobj.getString("header"));
haberModel1.setUrl(dataobj.getString("picture"));
haberModel1.setId(dataobj.getString("id"));
haberModelArrayList.add(haberModel1);
setupRecycler();
}
} catch (JSONException e) {
Log.d(""+TAG,e.printStackTrace() );
}
}
private void setupRecycler() {
lManager = new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(lManager);
rvAdapter = new RvAdapter(this, haberModelArrayList);
recyclerView.setAdapter(rvAdapter);
isLoading = false;
}
If rvAdapter is non-null, then add items to it and call notifyItemRangeInserted() instead of creating a new adapter:
for (int i = 0; i < dataArray.length(); i++) {
JSONObject dataobj = dataArray.getJSONObject(i);
haberModel1.setTitle(dataobj.getString("header"));
haberModel1.setUrl(dataobj.getString("picture"));
haberModel1.setId(dataobj.getString("id"));
haberModelArrayList.add(haberModel1);
// remove line: setupRecycler();
}
// Add these lines
if (rvAdapter != null){
int itemCount = rvAdapter.getItemCount();
// TODO: add method setItems() to your adapter
rvAdapter.setItems(haberModelArrayList);
rvAdapter.notifyItemRangeInserted(itemCount, dataArray.length());
} else {
setupRecycler();
}

Android - Firestore infinite pagination with listeners

I am making android chat app with firebase firestore database a I need infinite pagination with listeners for data changes (new massage, deleted massage...)
I found blog post written in kotlin and of corse searched firebase documentation and end up with this code:
// firstTime variable shows if function is called from pagination or initially
private void addMessagesEventListener(boolean firstTime) {
// get collection
CollectionReference messagesCollection = chatsCollection.document(chat.getId()).collection(Constants.FIREBASE_MESSAGES_PATH);
// create query
Query query = messagesCollection.orderBy("timestamp", Query.Direction.DESCENDING);
// if NOT first time add startAt
if (!firstTime) {
query.startAt(startTimestamp);
}
//limit to 20 messages
query.limit(20).get().addOnSuccessListener(queryDocumentSnapshots -> {
if (!firstTime) {
endTimestamp = startTimestamp;
}
startTimestamp = (long) queryDocumentSnapshots.getDocuments().get(queryDocumentSnapshots.size() - 1).get("timestamp");
Query innerQuery = messagesCollection.orderBy("timestamp").startAt(startTimestamp);
if(!firstTime) {
innerQuery.endBefore(endTimestamp);
}
ListenerRegistration listener = innerQuery
.addSnapshotListener((queryDocumentSnapshots1, e) -> {
if (e != null) {
Log.w(TAG, "listen:error", e);
return;
}
for (DocumentChange dc : queryDocumentSnapshots1.getDocumentChanges()) {
Message message = dc.getDocument().toObject(Message.class);
switch (dc.getType()) {
case ADDED:
// add new message to list
messageListAdapter.addMessage(message);
if (firstTime) {
messagesList.smoothScrollToPosition(0);
}
break;
case REMOVED:
// remove message from list
messageListAdapter.removeMessage(message);
break;
}
}
});
listeners.add(listener);
});
}
Now, code suppose to save listeners 1st for first 20 messages and new messages, 2nd for messages from 20-40 and so on, but, it is not working for some reason. Am I missing something?
Problem is that line
startTimestamp = (long) queryDocumentSnapshots.getDocuments().get(queryDocumentSnapshots.size() - 1).get("timestamp"); gets always the same result. I tried even with documentSnapshot instead of timestamp, same result.
Thanks in advance.
try this
#Override
public void onStart() {
super.onStart();
loadFirstQuery();
}
public void loadFirstQuery() {
if (firebaseAuth.getCurrentUser() != null) {
contentListDashboard.clear();
String currentUserId = firebaseAuth.getCurrentUser().getUid();
// what we do when recycler reach bottom
recyclerProfileDashboard.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// horizontal
//Boolean reachBottom = !recyclerView.canScrollHorizontally(-1);
// for vertical recycler
Boolean reachBottom = !recyclerView.canScrollVertically(-1);
if (reachBottom) {
loadMorePost(); // do load more post
}
}
});
// RETRIEVING FIRST Query
Query firstQuery = firebaseFirestore
.collection("ProfileDashboard")
.document(currentUserId)
.collection("ProfileInfo")
.orderBy("timestamp", Query.Direction.DESCENDING)
.limit(20);
firstQuery.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
if (!documentSnapshots.isEmpty()) {
// please add if doc not empty
if (isFirstPageFirstLoad) {
lastVisible = documentSnapshots.getDocuments().get(documentSnapshots.size() - 1); // array 0, 1, 2
}
for (DocumentChange doc : documentSnapshots.getDocumentChanges()) {
if (doc.getType() == DocumentChange.Type.ADDED) {
//String postId = doc.getDocument().getId();
contentProfileDashboard = doc.getDocument().toObject(ContentProfileDashboard.class);
// if first page firest load true
if (isFirstPageFirstLoad) {
contentListDashboard.add(contentProfileDashboard);
} else {
contentListDashboard.add(0, contentProfileDashboard);
}
// fire the event
adapterProfileDashboard.notifyDataSetChanged();
}
}
isFirstPageFirstLoad = false;
}
}
});
}
}
// Method to load more post
public void loadMorePost() {
if (firebaseAuth.getCurrentUser() != null) {
String currentUserId = firebaseAuth.getCurrentUser().getUid();
Query nextQuery = firebaseFirestore
.collection("ProfileDashboard")
.document(currentUserId)
.collection("ProfileInfo")
.orderBy("timestamp", Query.Direction.DESCENDING)
.startAfter(lastVisible)
.limit(20);
nextQuery.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
if (!documentSnapshots.isEmpty()) {
lastVisible = documentSnapshots.getDocuments().get(documentSnapshots.size() - 1);
for (DocumentChange doc : documentSnapshots.getDocumentChanges()) {
if (doc.getType() == DocumentChange.Type.ADDED) {
//String postId = doc.getDocument().getId();
// contentSeen = doc.getDocument().toObject(ContentProfile.class);
// contentList.add(contentSeen);
contentProfileDashboard = doc.getDocument().toObject(ContentProfileDashboard.class);
contentListDashboard.add(contentProfileDashboard);
//adapterSeen.notifyDataSetChanged();
adapterProfileDashboard.notifyDataSetChanged();
}
}
}
}
});
}
}
any question?
I have found mistake.
The working code is:
private void addMessagesEventListener(boolean firstTime) {
CollectionReference messagesCollection = chatsCollection.document(chat.getId()).collection(Constants.FIREBASE_MESSAGES_PATH);
Query query = messagesCollection.orderBy("timestamp", Query.Direction.DESCENDING);
if (!firstTime) {
query = query.startAt(startListen);
}
query.limit(20).get().addOnSuccessListener(queryDocumentSnapshots -> {
if (!firstTime) {
endListen = startListen;
}
startListen = queryDocumentSnapshots.getDocuments().get(queryDocumentSnapshots.size() - 1);
Query innerQuery = messagesCollection.orderBy("timestamp").startAt(startListen);
if(!firstTime) {
innerQuery = innerQuery.endBefore(endListen);
}
ListenerRegistration listener = innerQuery
.addSnapshotListener((queryDocumentSnapshots1, e) -> {
if (e != null) {
Log.w("SASA", "listen:error", e);
return;
}
for (DocumentChange dc : queryDocumentSnapshots1.getDocumentChanges()) {
Message message = dc.getDocument().toObject(Message.class);
switch (dc.getType()) {
case ADDED:
// add new message to list
messageListAdapter.addMessage(message);
if (firstTime) {
messagesList.smoothScrollToPosition(0);
}
break;
case REMOVED:
// remove message from list
messageListAdapter.removeMessage(message);
break;
}
}
});
listeners.add(listener);
});
}
The mistake was in query = query.startAt(startListen) and innerQuery = innerQuery.endBefore(endListen)
startListen & endListen are of DocumentSnapshot type
I am using sortedList in my adapter
You shoud add
private void detachListeners() {
for(ListenerRegistration registration : listeners) {
registration.remove();
}
}
in onDestroy to detach all listeners.
Code is listening for adding new messages and deleting old ones.

Recycler View infinite scroll not working properly

I am getting data from TMDB and displaying it in a recycler view. I wanted to use the infinite scroll recycler view, so I saw some tutorials and implemented it. The problem is that after first load , the whole data gets refreshed with new data after scrolling through the first 5 elements. How do I fix this?
EndlessRecyclerViewScrollListener.java
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 = 15;
// The current offset index of data you have loaded
private int currentPage = 1;
// 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 = 1;
RecyclerView.LayoutManager mLayoutManager;
public EndlessRecyclerViewScrollListener(LinearLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
}
public EndlessRecyclerViewScrollListener(GridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
public EndlessRecyclerViewScrollListener(StaggeredGridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
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 StaggeredGridLayoutManager) {
int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null);
// get maximum element within the list
lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions);
} else if (mLayoutManager instanceof GridLayoutManager) {
lastVisibleItemPosition = ((GridLayoutManager) mLayoutManager).findLastVisibleItemPosition();
} else 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);/ The minimum amount of items to have below your current scroll position
// before loading more.
private int visibleThreshold = 15;
// The current offset index of data you have loaded
private int currentPage = 1;
// 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 = 1;
RecyclerView.LayoutManager mLayoutManager;
public EndlessRecyclerViewScrollListener(LinearLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
}
public EndlessRecyclerViewScrollListener(GridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
public EndlessRecyclerViewScrollListener(StaggeredGridLayoutManager layoutManager) {
this.mLayoutManager = layoutManager;
visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
}
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 StaggeredGridLayoutManager) {
int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null);
// get maximum element within the list
lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions);
} else if (mLayoutManager instanceof GridLayoutManager) {
lastVisibleItemPosition = ((GridLayoutManager) mLayoutManager).findLastVisibleItemPosition();
} else 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);}}
MainActivity.java
public class MainActivity extends AppCompatActivity implemens ConnectivityReceiver.ConnectivityReceiverListener {
private static final String API_KEY = "***************";
private static final String TAG = "MainActivity";
private int page = 1;
private TextView no_data_tv;
private RecyclerView mainMoviesView;
private View noInternetLayout;
private ProgressBar progressBar;
private EndlessRecyclerViewScrollListener scrollListener;
private LinearLayoutManager llm;
List<Movies> movies;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
no_data_tv = (TextView) findViewById(R.id.text_no_data);
movies = new ArrayList<>();
llm = new LinearLayoutManager(this);
mainMoviesView = (RecyclerView) findViewById(R.id.main_recycler_view);
mainMoviesView.setLayoutManager(llm);
// This is the layout which is displayed if there is no internet connection. It is currently set to View.INVISIBLE
noInternetLayout = findViewById(R.id.no_internet_layout);
noInternetLayout.setVisibility(View.INVISIBLE);
progressBar = (ProgressBar) findViewById(R.id.loading_main_activity);
if(checkConnetion())
{
getDataFromServer(page);
progressBar.setVisibility(View.INVISIBLE);
}else
{
noInternetLayout.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.INVISIBLE);
}
scrollListener = new EndlessRecyclerViewScrollListener(llm) {
#Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
getDataFromServer(page);
Log.v(TAG,"Page loaded is"+page);
}
};
mainMoviesView.addOnScrollListener(scrollListener);
}
private boolean checkConnetion() {
return ConnectivityReceiver.isConnected();
}
private void getDataFromServer(int page)
{
// These are the retrofit codes to get the data from TMDB API
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
Call<Response> call = apiService.getPopularMovies(API_KEY , page);
call.enqueue(new Callback<Response>() {
#Override
public void onResponse(Call<Response> call, retrofit2.Response<Response> response) {
List<Movies> movies = response.body().getMovies();
progressBar.setVisibility(View.INVISIBLE);
if(movies.size() == 0)
{
no_data_tv.setVisibility(View.VISIBLE);
}else{
mainMoviesView.setAdapter(new MoviesAdapter(movies,MainActivity.this));
}
}
#Override
public void onFailure(Call<Response> call, Throwable t) {
Log.e(TAG,t.toString());
}
});
}
#Override
protected void onResume() {
super.onResume();
// register connection status listener
MyApplication.getInstance().setConnectivityListener(this);
}
#Override
public void onNetworkConnectionChanged(boolean isConnected) {
if(isConnected)
{
getDataFromServer(page);
}else{
progressBar.setVisibility(View.INVISIBLE);
noInternetLayout.setVisibility(View.VISIBLE);
}
}}
Where have I gone wrong?
Dude,
You are assigning new values each time you call,
Look at this line -
List<Movies> movies = response.body().getMovies();
You must add elements into dataset,
movies.addAll(response.body().getMovies());
This line always initialize yourview with new data
mainMoviesView.setAdapter(new MoviesAdapter(movies,MainActivity.this));
It would be in onCreate(), onCreateView() or other initializing method.
MoviesAdapter moviesAdapter = new MoviesAdapter(movies,MainActivity.this);
mainMoviesView.setAdapter(moviesAdepter);
And then your new call enqueue.
call.enqueue(new Callback<Response>() {
#Override
public void onResponse(Call<Response> call, retrofit2.Response<Response> response) {
movies.addAll(response.body().getMovies()); // this line updated your movies list.
progressBar.setVisibility(View.INVISIBLE);
if(movies.size() == 0)
{
no_data_tv.setVisibility(View.VISIBLE);
}else{
moviesAdapter.notifyDataSetChanged(); // this new line.
}
}
#Override
public void onFailure(Call<Response> call, Throwable t) {
Log.e(TAG,t.toString());
}
});

Categories

Resources