I'm building an app which will show videos stored on firebase. The list of videos needs to be paginated fetching most recent 20 videos at a time.
Here is the code I thought would work
private void getVideos() {
Query videosQuery = FirebaseUtil.getVideosRef();
videosQuery.startAt(0);
videosQuery.endAt(1);
ChildEventListener videosChildEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String date = dataSnapshot.getKey();
String temp = date;
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d(tag, "database error");
}
};
ValueEventListener videoValueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String date = dataSnapshot.getKey();
String temp = date;
long count = dataSnapshot.getChildrenCount();
String value = dataSnapshot.getValue().toString();
temp = value;
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d(tag, "database error");
}
};
// videosQuery.addChildEventListener(videosChildEventListener);
videosQuery.addValueEventListener(videoValueEventListener);
}
But above code retrieves entire list of videos instead of limited videos. How can pagination be implemented.
Below is the code I'm using for pagination which shows the latest node first.
public void getImages() {
Query imagesQuery = FirebaseDatabase.getInstance().getReference().child("englishDps").child(mChildName).orderByKey().limitToLast(21);
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Image image = dataSnapshot.getValue(Image.class);
image.setNodeKey(dataSnapshot.getKey());
mTempImages.add(image);
if (mTempImages.size() == 21) {
mLastKey = mTempImages.get(0).getNodeKey();
Collections.reverse(mTempImages);
mTempImages.remove(mTempImages.size() - 1);
mImages.addAll(mTempImages);
setAdapter();
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
if (isAdded()) {
Toast.makeText(getActivity(), "Problem loading more images...", Toast.LENGTH_LONG).show();
}
}
};
imagesQuery.addChildEventListener(childEventListener);
}
#Override
public void getMoreImages() {
if (!mGettingMoreImages) {
mGettingMoreImages = true;
Query imagesQuery = FirebaseDatabase.getInstance().getReference("englishDps").child(mChildName).orderByKey().endAt(mLastKey).limitToLast(21);
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Image image = dataSnapshot.getValue(Image.class);
image.setNodeKey(dataSnapshot.getKey());
mMoreImages.add(image);
if (mMoreImages.size() == 21) {
mLastKey = mMoreImages.get(0).getNodeKey();
Collections.reverse(mMoreImages);
mMoreImages.remove(mMoreImages.size() - 1);
mImages.addAll(mMoreImages);
mMoreImages.clear();
mGettingMoreImages = false;
mImagesAdapter.notifyDataSetChanged();
return;
}
if (mLastKey.equalsIgnoreCase(image.getNodeKey())) {
Collections.reverse(mMoreImages);
mImages.addAll(mMoreImages);
mMoreImages.clear();
mGettingMoreImages = false;
mImagesAdapter.onNoMoreImages();
;
mImagesAdapter.notifyDataSetChanged();
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
if (isAdded()) {
Toast.makeText(getActivity(), "Problem loading more images...", Toast.LENGTH_LONG).show();
}
}
};
imagesQuery.addChildEventListener(childEventListener);
}
}
I have following method to paginate through a firebase realtime database node:
private void getUsers(String nodeId) {
Query query;
if (nodeId == null)
query = FirebaseDatabase.getInstance().getReference()
.child(Consts.FIREBASE_DATABASE_LOCATION_USERS)
.orderByKey()
.limitToFirst(mPostsPerPage);
else
query = FirebaseDatabase.getInstance().getReference()
.child(Consts.FIREBASE_DATABASE_LOCATION_USERS)
.orderByKey()
.startAt(nodeId)
.limitToFirst(mPostsPerPage);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
UserModel user;
List<UserModel> userModels = new ArrayList<>();
for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) {
userModels.add(userSnapshot.getValue(UserModel.class));
}
mAdapter.addAll(userModels);
mIsLoading = false;
}
#Override
public void onCancelled(DatabaseError databaseError) {
mIsLoading = false;
}
});
}
Every time I reach the bottom of the paginated data, I call the getUsers(mAdapter.getLastItemId()); and then it brings the next set of records.
I have written a complete guide with open source sample app on this that you can check at https://blog.shajeelafzal.com/2017/12/13/firebase-realtime-database-pagination-guide-using-recyclerview/
You want to be using the limitToFirst/limitToLast methods to retrieve a limited number of results.
videosQuery.orderByKey().limitToFirst(20)
https://www.firebase.com/docs/web/api/query/limittofirst.html
You should really consider changing the naming convention of your videos to include leading 0s (i.e. video01, video02... video10, video11) because the above code will display them exactly as you have them above (which I assume is out of order?)
Alternatively, if you're adding the videos via Java, you could just let firebase create the uniqueids via push(). The uniqueid are generated in a way that they'll sort chronilogically, which sounds like it'll suit your need to grab the most recent(ly added?) videos.
https://www.firebase.com/docs/web/api/firebase/push.html
mPageEndOffset = 0;
mPageLimit = 10;
mPageEndOffset += mPageLimit;
deviceListQuery = mDatabase.child("users")
.orderByChild("id").limitToFirst(mPageLimit).startAt(mPageEndOffset);
deviceListQuery.addValueEventListener(YourActivity.this);
You can achieve it by using Firebase database paging library as below code...
In this code, I have shown Post as an data model item and PostViewHolder as ViewHolder
//Initialize RecyclerView
mRecyclerView = findViewById(R.id.recycler_view);
mRecyclerView.setHasFixedSize(true);
LinearLayoutManager mManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mManager);
//Initialize Database
mDatabase = FirebaseDatabase.getInstance().getReference().child("posts");
//Initialize PagedList Configuration
PagedList.Config config = new PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setPrefetchDistance(5)
.setPageSize(10)
.build();
//Initialize FirebasePagingOptions
DatabasePagingOptions<Post> options = new DatabasePagingOptions.Builder<Post>()
.setLifecycleOwner(this)
.setQuery(mDatabase, config, Post.class)
.build();
//Initialize Adapter
mAdapter = new FirebaseRecyclerPagingAdapter<Post, PostViewHolder>(options) {
#NonNull
#Override
public PostViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new PostViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false));
}
#Override
protected void onBindViewHolder(#NonNull PostViewHolder holder,
int position,
#NonNull Post model) {
holder.setItem(model);
}
#Override
protected void onLoadingStateChanged(#NonNull LoadingState state) {
switch (state) {
case LOADING_INITIAL:
case LOADING_MORE:
// Do your loading animation
mSwipeRefreshLayout.setRefreshing(true);
break;
case LOADED:
// Stop Animation
mSwipeRefreshLayout.setRefreshing(false);
break;
case FINISHED:
//Reached end of Data set
mSwipeRefreshLayout.setRefreshing(false);
break;
case ERROR:
retry();
break;
}
}
#Override
protected void onError(#NonNull DatabaseError databaseError) {
super.onError(databaseError);
mSwipeRefreshLayout.setRefreshing(false);
databaseError.toException().printStackTrace();
}
};
//Set Adapter to RecyclerView
mRecyclerView.setAdapter(mAdapter);
Just visit this below URL for reference
https://firebaseopensource.com/projects/patilshreyas/firebaserecyclerpagination/app/readme.md/
Here you will find implementation of library which helps to implement Pagination of firebase data in RecyclerView
I hope this will help you!
This is how I implemented pagination from firebase database. Consider a case if we have 100 messages. So I first load last 20 messages from firebase i.e. 81 to 100. Then on scroll up I call getMoreMessages() function to load next 20 messages which are 61 to 80 and so on.
public class ChatActivity extends Activity {
String chat_id = "";
long mTotalChildren = 0;
boolean loading = false;
ChildEventListener childEventListenerMain, childEventListenerPager;
ChatActivity mContext = ChatActivity.this;
MessageAdapter messageAdapter;
#BindView(R.id.pb_messages)
ProgressBar pb_messages;
#BindView(R.id.ll_audio)
LinearLayout llAudio;
#BindView(R.id.tv_record_time)
AppCompatTextView tvRecordTime;
#BindView(R.id.tv_cancel)
AppCompatTextView tvCancel;
#BindView(R.id.iv_send)
AppCompatImageView ivSend;
#BindView(R.id.iv_record)
AppCompatImageView ivRecord;
#BindView(R.id.ab_layout)
AppBarLayout abLayout;
#BindView(R.id.messages)
RecyclerView rvMessages;
#BindView(R.id.iv_chat_icon)
SimpleDraweeView ivChatIcon;
#BindView(R.id.iv_camera)
AppCompatImageView ivCamera;
#BindView(R.id.iv_gallery)
AppCompatImageView ivGallery;
#BindView(R.id.message_input)
AppCompatEditText messageInput;
#BindView(R.id.tv_send)
AppCompatTextView tvSend;
#BindView(R.id.toolbar_title)
AppCompatTextView toolbarTitle;
#BindView(R.id.toolbar_status)
AppCompatTextView toolbarStatus;
#BindView(R.id.ll_send)
LinearLayout llSend;
int categoryId, senderId, receiverId, offerId;
String mLastKey;
LinearLayoutManager layoutManager;
private ArrayList<MessageModel> messageArrayList = new ArrayList<>();
private ArrayList<MessageModel> tempMessageArrayList = new ArrayList<>();
#Override
public int getLayoutId() {
return R.layout.activity_chat;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
messageAdapter = new MessageAdapter(mContext, messageArrayList) {
};
layoutManager = new LinearLayoutManager(mContext);
rvMessages.setLayoutManager(layoutManager);
rvMessages.setItemAnimator(new DefaultItemAnimator());
rvMessages.setAdapter(messageAdapter);
rvMessages.setHasFixedSize(true);
rvMessages.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);
if (messageArrayList.size() >= 20 &&
!loading && layoutManager.findFirstVisibleItemPosition() == 0 && messageArrayList.size() < mTotalChildren) {
loading = true;
getMoreMessages();
}
}
});
messageAdapter.notifyDataSetChanged();
//used to scroll up recyclerview when keyboard pops up
rvMessages.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View view, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
if (bottom < oldBottom) {
rvMessages.postDelayed(new Runnable() {
#Override
public void run() {
rvMessages.scrollToPosition(messageArrayList.size() - 1);
}
}, 100);
}
}
});
loading = true;
getMessages();
}
public void getMessages() {
FirebaseDatabase.getInstance().getReference().child(pathtomsgs).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.e("childrenCount", String.valueOf(+dataSnapshot.getChildrenCount()));
mTotalChildren = dataSnapshot.getChildrenCount();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Query messageQuery = FirebaseDatabase.getInstance().getReference().child(pathtomsgs).limitToLast(20);
childEventListenerMain = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
loading = true;
MessageModel messageModel = dataSnapshot.getValue(MessageModel.class);
if (messageModel != null) {
messageModel.chat_id = chat_id;
messageModel.message_id = dataSnapshot.getKey();
messageArrayList.add(messageModel);
messageAdapter.notifyDataSetChanged();
mLastKey = messageArrayList.get(0).message_id;
rvMessages.scrollToPosition(messageArrayList.size() - 1);
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(mContext, "Problem loading more images...", Toast.LENGTH_LONG).show();
}
};
messageQuery.addChildEventListener(childEventListenerMain);
ValueEventListener messageChildSINGLEValueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
pb_messages.setVisibility(View.GONE);
System.out.println("We're done loading messages " + dataSnapshot.getChildrenCount() + " items");
loading = false;
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
messageQuery.addListenerForSingleValueEvent(messageChildSINGLEValueEventListener);
}
public void getMoreMessages() {
tempMessageArrayList.clear();
Query messageQuery = FirebaseDatabase.getInstance().getReference().child(pathtomsgs).orderByKey().endAt(mLastKey).limitToLast(20);
childEventListenerPager = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
loading = true;
MessageModel messageModel = dataSnapshot.getValue(MessageModel.class);
if (messageModel != null) {
messageModel.chat_id = chat_id;
messageModel.message_id = dataSnapshot.getKey();
tempMessageArrayList.add(messageModel);
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(mContext, "Problem loading more images...", Toast.LENGTH_LONG).show();
}
};
messageQuery.addChildEventListener(childEventListenerPager);
ValueEventListener messageChildSINGLEValueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
System.out.println("We're done loading messages " + dataSnapshot.getChildrenCount() + " items");
tempMessageArrayList.remove(tempMessageArrayList.size() - 1);
messageArrayList.addAll(0, tempMessageArrayList);
mLastKey = messageArrayList.get(0).message_id;
messageAdapter.notifyDataSetChanged();
//rvMessages.scrollToPosition(20);
layoutManager.scrollToPositionWithOffset(19, 0);
loading = false;
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
messageQuery.addListenerForSingleValueEvent(messageChildSINGLEValueEventListener);
}
#Override
protected void onDestroy() {
FirebaseDatabase.getInstance().getReference().child(pathtomsgs).removeEventListener(childEventListenerPager);
FirebaseDatabase.getInstance().getReference().child(pathtomsgs).removeEventListener(childEventListenerMain);
super.onDestroy();
}
}
Android paging library can be used to implement pagination for data fetched from firebase database. Data is displayed in recycler view and paging component fetches pages in response to user scroll events.
Paging data source calls your firebase DAO object passing query parameters for the page to be displayed and results are passed back to paging component using callback provided to it.
Here is a complete example for reference http://www.zoftino.com/firebase-pagination-using-android-paging-library
accepted answear dos not work when less then the max. itmes (21) in database.
this is my solution build on the accepted answer:
0)set variables
private String lastMessageKey;
private int totalItemCount;
private int lastVisibleItem;
private boolean isLoadingMoreFollowers = false;
private boolean hasMoreItems = true;
private boolean hasShownNoMoreItemsToast = false;
private boolean initialLoad = true;
private final int MAX_LOAD_ITEMS = 11;
private final int VISIBLE_TRESHOLD = 1;
1) set a listener:
private void setMessageListener() {
if (childEventListener == null) {
mmessageArrayList.clear();
final ArrayList<Mmessage> tempMmessages = new ArrayList<>();
query = mDatabaseInstace.getReference().child(chat1).child(F.CHATS).child(F.MESSAGES).orderByKey().limitToLast(MAX_LOAD_ITEMS-1);
childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
Log.d(TAG, "onChildAdded: -----------------> " + dataSnapshot);
Log.d(TAG, "onChildAdded: -----------------> " + s);
tempMmessages.add(dataSnapshot.getValue(Mmessage.class));
preloadMessagePics(tempMmessages);
if (initialLoad) {
lastMessageKey = tempMmessages.get(0).getMessagePushKey();
initialLoad = false;
}
mmessageArrayList.add(tempMmessages.size()-1, tempMmessages.get(0));
messageAdapter.notifyDataSetChanged();
tempMmessages.clear();
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
Log.d(TAG, "onChildChanged: --------------------------------->");
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved: ---------------------------------->");
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
Log.d(TAG, "onChildMoved: ------------------------------------>");
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d(TAG, "onCancelled: ------------------------------------->");
}
};
query.addChildEventListener(childEventListener);
}
}
2) set load more listener:
private void setLoadMoreListener(){
setup.RV_messages.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = linearLayoutManager.getItemCount();
lastVisibleItem = linearLayoutManager.findLastVisibleItemPosition();
if (!isLoadingMoreFollowers && totalItemCount <= (lastVisibleItem+VISIBLE_TRESHOLD) && (totalItemCount >= MAX_LOAD_ITEMS-1)){
if (hasMoreItems) {
getMoreMessages();
Toast.makeText(homeActivity, "load more items", Toast.LENGTH_SHORT).show();
}else {
if (!hasShownNoMoreItemsToast) {
Toast.makeText(homeActivity, "has no more items", Toast.LENGTH_SHORT).show();
hasShownNoMoreItemsToast = true;
}
}
}
}
});
}
3) get more items:
private void getMoreMessages(){
final ArrayList<Mmessage> tempMmessages = new ArrayList<>();
isLoadingMoreFollowers = true;
loadMoreQuery = mDatabaseInstace.getReference().child(chat1).child(F.CHATS).child(F.MESSAGES).orderByKey().endAt(lastMessageKey).limitToLast(MAX_LOAD_ITEMS);
loadMoreChildEventListener = new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
tempMmessages.add(dataSnapshot.getValue(Mmessage.class));
preloadMessagePics(tempMmessages);
if (tempMmessages.size() == MAX_LOAD_ITEMS){
lastMessageKey = tempMmessages.get(0).getMessagePushKey();
Collections.reverse(tempMmessages);
tempMmessages.remove(0);
mmessageArrayList.addAll(tempMmessages);
isLoadingMoreFollowers = false;
messageAdapter.notifyDataSetChanged();
tempMmessages.clear();
return;
}
if (lastMessageKey.equalsIgnoreCase(tempMmessages.get(tempMmessages.size()-1).getMessagePushKey())){
Collections.reverse(tempMmessages);
tempMmessages.remove(0);
mmessageArrayList.addAll(tempMmessages);
isLoadingMoreFollowers = false;
hasMoreItems = false;
messageAdapter.notifyDataSetChanged();
tempMmessages.clear();
}
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
loadMoreQuery.addChildEventListener(loadMoreChildEventListener);
}
have fun!!
If you want to get list from firebase realtime database descending with pagination you need use smth like this:
Query query = myRef.child("stories").orderByChild("takenAt").endAt(1600957136000L).limitToLast(30);
Full code, two requests
List<Story> storyList = new ArrayList<>();
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference();
//first request will be look like this
Query query = myRef.child("stories").orderByChild("takenAt").endAt(1600957136000L).limitToLast(30);
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Story story = snapshot.getValue(Story.class);
storyList.add(story);
}
}
Collections.reverse(storyList);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Log.e("ptg", "onCancelled: ", error.toException());
}
});
//second request
long lastTakenAtInTheStoryList = storyList.get(storyList.size()-1).getTakenAt();
Query query2 = myRef.child("stories").orderByChild("takenAt").endAt(lastTakenAtInTheStoryList).limitToLast(30);
query2.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
Story story = snapshot.getValue(Story.class);
storyList.add(story);
}
}
Collections.reverse(storyList);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Log.e("ptg", "onCancelled: ", error.toException());
}
});
In the past (but no longer) a question regarding implementing Pagination to a query on Firestore was marked as a duplicate of this question I will answer for FireStore here.
Paginate a query on android Firestore
Query query = db.collection("cities")
.orderBy("population")
.limit(25);
Query next = query;
private void loadCities() {
query = next;
query.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot documentSnapshots) {
// Get the last visible document
DocumentSnapshot lastVisible =
documentSnapshots.getDocuments()
.get(documentSnapshots.size() -1);
// Construct a new query starting at this document,
// get the next 25 cities.
next = db.collection("cities")
.orderBy("population")
.startAfter(lastVisible)
.limit(25);
}
});
}
Now just call the loadCities() method whenever you need to load more cities.
Related
I have issue with two of these listeners. Below is the scenario.
When i first load the page, in order to prevent "onChildAdded" from addChildEventListener to get fired before "onDataChange" from addListenerForSingleValueEvent, i implement following code.
#Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState)
{
//List object initialization
itemList1 = new ArrayList<>();
itemList2 = new ArrayList<>();
check = false;
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_nested_recycler_view, container, false);
recyclerView = view.findViewById(R.id.nestedRecyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
readData(new FirebaseCallback()
{
#Override
public void onCallBack(List<DonationRequestDetailsModel> list1, List<DonationRequestDetailsModel> list2)
{
if (list1.size() == 0)
{
confirmationAdapter1 = new ConfirmationAdapter(list2, item, location, email, getActivity());
recyclerView.setAdapter(confirmationAdapter1);
check = true;
}
else if(list1.size() == 1)
{
confirmationAdapter2 = new ConfirmationAdapter(list1, item, location, email, getActivity());
recyclerView.setAdapter(confirmationAdapter2);
check = true;
}
}
});
return view;
}
private interface FirebaseCallback
{
void onCallBack(List<DonationRequestDetailsModel> list1, List<DonationRequestDetailsModel> list2);
}
private void readData(final FirebaseCallback firebaseCallback)
{
//Loop through data in Firebase Database based on corresponding email and add data into List
reference = FirebaseDatabase.getInstance().getReference();
xreference = reference.child("Benefactor Request");
xreference.addListenerForSingleValueEvent(new ValueEventListener()
{
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot)
{
for (DataSnapshot snapshot : dataSnapshot.getChildren())
{
if (snapshot.child("donaterEmail").getValue().toString().equals(email) && snapshot.child("meetingLocation").getValue().toString().equals(location) && snapshot.child("itemDescription").getValue().toString().equals(item) && snapshot.child("status").getValue().toString().equals("Accepted") )
{
itemList1.add(new DonationRequestDetailsModel(snapshot.child("benefactorName").getValue().toString(), snapshot.child("benefactorEmail").getValue().toString(), snapshot.child("dateandtime").getValue().toString(), snapshot.child("remark").getValue().toString()));
}
else if (snapshot.child("donaterEmail").getValue().toString().equals(email) && snapshot.child("meetingLocation").getValue().toString().equals(location) && snapshot.child("itemDescription").getValue().toString().equals(item) && snapshot.child("status").getValue().toString().equals("Pending") )
{
itemList2.add(new DonationRequestDetailsModel(snapshot.child("benefactorName").getValue().toString(), snapshot.child("benefactorEmail").getValue().toString(), snapshot.child("dateandtime").getValue().toString(), snapshot.child("remark").getValue().toString()));
}
}
firebaseCallback.onCallBack(itemList1, itemList2);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError)
{
}
});
xreference.addChildEventListener(new ChildEventListener()
{
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s)
{
if(check)
{
itemList2.add(new DonationRequestDetailsModel(dataSnapshot.child("benefactorName").getValue().toString(), dataSnapshot.child("benefactorEmail").getValue().toString(), dataSnapshot.child("dateandtime").getValue().toString(), dataSnapshot.child("remark").getValue().toString()));
confirmationAdapter1.notifyDataSetChanged();
}
else
{
}
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s)
{
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot)
{
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s)
{
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError)
{
}
});
}
}
However, when i press back from the page, and click into the page again, "onDataChange" from addListenerForSingleValueEvent gets fired before "onChildAdded" from addChildEventListener, why?
I'm building a chat app which have post feature, When I create a post in NewPostActivity, the image and text are uploaded (because I can see them in firebase Database tree) but The problem is nothing is shown in my MainActivity which is supposed to display my posts.
I used Firebase UI for the Rv but I'm not sure is the problem lies in NewPostActivity or the MainActivity.
I tried to run the debugger to see but there is no error or null point exception.
NewPostActivity.java
btnPost.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startPosting();
}
});
}
private void startPosting() {
progressDialog=new ProgressDialog(NewPostActivity.this);
progressDialog.setTitle("Uploading Image");
progressDialog.setMessage("Please Wait while we process the image");
progressDialog.setCanceledOnTouchOutside(false);
final String desc_val=mPostDesc.getText().toString().trim();
if(!TextUtils.isEmpty(desc_val) && mImageUri!=null){
progressDialog.show();
String random_name= random();
StorageReference filepath = storageReference.child("Blog_Images").child(random_name);
filepath.putFile(mImageUri).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
#Override
public void onComplete(#NonNull Task<UploadTask.TaskSnapshot> task) {
Task<Uri> uriTask = task.getResult().getStorage().getDownloadUrl();
while (!uriTask.isComplete());
final Uri downloadUrl = uriTask.getResult();
final DatabaseReference newPost = mRootRef.child("Blog").push();
final String user_id= mCurrentUser.getUid();
mRootRef.child("Users").child(user_id).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
newPost.child("desc").setValue(desc_val);
newPost.child("image").setValue(downloadUrl.toString());
newPost.child("user_id").setValue(user_id);
newPost.child("timestamp").setValue(ServerValue.TIMESTAMP);
newPost.child("username").setValue(dataSnapshot.child("name").getValue());
newPost.child("thumb_image").setValue(dataSnapshot.child("thumb_image").getValue());
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
progressDialog.dismiss();
startActivity(new Intent(NewPostActivity.this,MainActivity.class));
finish();
}
});
}
}
MainActivity.java
Query conversationQuery = mDatabase.orderByChild("timestamp");
FirebaseRecyclerOptions<Blog> options = new FirebaseRecyclerOptions.Builder<Blog>()
.setQuery(conversationQuery, Blog.class)
.build();
FirebaseRecyclerAdapter<Blog, BlogViewHolder> firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Blog, BlogViewHolder>(options) {
#NonNull
#Override
public BlogViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.post_single_layout, parent, false);
mAuth = FirebaseAuth.getInstance();
return new BlogViewHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull final BlogViewHolder viewHolder, int position, #NonNull final Blog model) {
viewHolder.setContext(getApplicationContext());
final String list_blog_id = getRef(position).getKey();
viewHolder.setLikeBtns(list_blog_id);
Query lastMessageQuery = mDatabase.child(list_blog_id).limitToLast(1);
lastMessageQuery.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
viewHolder.setDesc(model.getDesc());
viewHolder.setImage(model.getImage());
viewHolder.setUsername(model.getUsername());
viewHolder.setStatus(model.getStatus());
viewHolder.setPostImage(model.getThumb_image());
viewHolder.setTime(model.getTimestamp());
userID = model.getUid();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
viewHolder.postImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent imageFullScreen = new Intent(getApplicationContext(), PhotoActivity.class);
imageFullScreen.putExtra("uid", list_blog_id);
imageFullScreen.putExtra("from", "RequestsFragment");
startActivity(imageFullScreen);
}
});
viewHolder.mLikeBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mProcessLike = true;
mDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (mProcessLike) {
if (dataSnapshot.child(list_blog_id).hasChild(mAuth.getCurrentUser().getUid())) {
mDatabaseLike.child(list_blog_id).child(mAuth.getCurrentUser().getUid()).removeValue();
mProcessLike = false;
} else {
mDatabaseLike.child(list_blog_id).child(mAuth.getCurrentUser().getUid()).setValue("Lliked");
mProcessLike = false;
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
}
};
mBlogList.setAdapter(firebaseRecyclerAdapter);
}
There is some parts of your code that are not shown, also as I don't see a screenshot of your database I don't know if I will give a correct answer, but obviously you need to start listening to the database before you get the data with firebase UI.
So before this:
mBlogList.setAdapter(firebaseRecyclerAdapter);
Add this:
firebaseRecyclerAdapter.startListening();
Refer to this to know more about how to set your firebase UI.
I am currently working on a chat application and have come across an issue. My Chat Fragment contains my Recyclerview which populates data from Firebase DB. I am able to obtain the data, but I am running into an issue. When I open my Chat Activity and send a message, a new push id is created with the information stored in the child. The data obtained by my recyclerview is it gets the last push id and retrieves the last message that was sent. The problem is, when I go back into my fragment, the recyclerview re-populates and adds the new push id last message that was created, and creates another item instead of just refreshing the original item.
So essentially, I will load my app, go into the Chat Fragment, my recyclerview will display the other user and the last message that was sent, no problem, then I will click on that item, open the chat activity, send a message then go back. Now when I am back into the chat fragment I will have two or three or however many messages that were sent displaying in the recyclerview. Not sure on how to fix this, my code is below:
DATABASE STRUCTURE
Chat Fragment
public class Fragment_MatchChats extends Fragment {
private RecyclerView mRecyclerView, mRecyclerViewChat;
private RecyclerView.Adapter mMatchesAdapter, mChatAdapter;
private String currentUserID;
private DatabaseReference mDatabaseChat;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag_match_chat, container, false);
currentUserID = FirebaseAuth.getInstance().getCurrentUser().getUid();
mDatabaseChat = FirebaseDatabase.getInstance().getReference().child("Chat");
LinearLayoutManager layoutManagerChat = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
mRecyclerViewChat = (RecyclerView) v.findViewById(R.id.recyclerViewChat);
mRecyclerViewChat.setHasFixedSize(true);
mRecyclerViewChat.setLayoutManager(layoutManagerChat);
mChatAdapter = new RecyclerViewChatAdapter(getDataSetChat(), getContext());
getUserMatchId();
return v;
}
//this method will get the user ID in the database that you matched with. It will run through the matches child and get all the user IDs
private void getUserMatchId() {
DatabaseReference matchDB = FirebaseDatabase.getInstance().getReference().child("Users").child(currentUserID).child("swipes").child("matches");
matchDB.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
for(DataSnapshot match : dataSnapshot.getChildren()){
CheckChatID(match.getKey());
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void CheckChatID(final String chat) {
DatabaseReference ChatDB = FirebaseDatabase.getInstance().getReference().child("Users").child(currentUserID).child("swipes").child("matches")
.child(chat).child("ChatID");
ChatDB.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
String ChatID = dataSnapshot.getValue().toString();
ChatIDExist(ChatID, chat);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void ChatIDExist(final String chatID, final String oppUserID) {
final DatabaseReference ChatDB = mDatabaseChat.child(chatID);
final Query lastQuery = ChatDB.orderByKey().limitToLast(1);
ChatDB.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
lastQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot child: dataSnapshot.getChildren()){
String key = child.child("text").getValue().toString();
FetchChatInfo(oppUserID,key);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void FetchChatInfo(String key, final String chatID) {
DatabaseReference userDB = FirebaseDatabase.getInstance().getReference().child("Users").child(key);
userDB.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
String matched_userID = dataSnapshot.getKey();
String matches_userName = "";
String matches_userProPic = "";
String match_CHATID = chatID;
if(dataSnapshot.child("name").getValue() != null){
matches_userName = dataSnapshot.child("name").getValue().toString();
}
if(dataSnapshot.child("profilePicURL").getValue() != null){
matches_userProPic = dataSnapshot.child("profilePicURL").getValue().toString();
}
RecyclerViewChatReference chat_obj = new RecyclerViewChatReference(matched_userID, matches_userName, matches_userProPic, match_CHATID);
resultsChats.add(chat_obj);
mRecyclerViewChat.setAdapter(mChatAdapter);
mChatAdapter.notifyDataSetChanged();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private ArrayList<RecyclerViewChatReference> resultsChats = new ArrayList<RecyclerViewChatReference>();
private List<RecyclerViewChatReference> getDataSetChat() {
return resultsChats;
}
Chat Activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
matchId = getIntent().getExtras().getString("matchID");
currentUserID = FirebaseAuth.getInstance().getCurrentUser().getUid();
mDatabaseUser = FirebaseDatabase.getInstance().getReference().child("Users").child(currentUserID)
.child("swipes").child("matches").child(matchId).child("ChatID");
mDatabaseChat = FirebaseDatabase.getInstance().getReference().child("Chat");
getChatId();
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mRecyclerView.setNestedScrollingEnabled(false);
mRecyclerView.setHasFixedSize(false);
mChatLayoutManager = new LinearLayoutManager(ChatActivity.this);
mRecyclerView.setLayoutManager(mChatLayoutManager);
mChatAdapter = new ChatAdapter(getDataSetChat(), ChatActivity.this);
mRecyclerView.setAdapter(mChatAdapter);
mSendEditText = findViewById(R.id.message);
mSendButton = findViewById(R.id.send);
mSendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sendMessage();
}
});
}
private void sendMessage() {
String sendMessageText = mSendEditText.getText().toString();
if(!sendMessageText.isEmpty()){
DatabaseReference newMessageDb = mDatabaseChat.push();
Map newMessage = new HashMap();
newMessage.put("createdByUser", currentUserID);
newMessage.put("text", sendMessageText);
newMessageDb.setValue(newMessage);
}
mSendEditText.setText(null);
}
private void getChatId(){
mDatabaseUser.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
chatId = dataSnapshot.getValue().toString();
mDatabaseChat = mDatabaseChat.child(chatId);
getChatMessages();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void getChatMessages() {
mDatabaseChat.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if(dataSnapshot.exists()){
String message = "";
String createdByUser = "";
if(dataSnapshot.child("text").getValue()!=null){
message = dataSnapshot.child("text").getValue().toString();
}
if(dataSnapshot.child("createdByUser").getValue()!=null){
createdByUser = dataSnapshot.child("createdByUser").getValue().toString();
}
if(message!=null && createdByUser!=null){
Boolean currentUserBoolean = false;
if(createdByUser.equals(currentUserID)){
currentUserBoolean = true;
}
ChatObject newMessage = new ChatObject(message, currentUserBoolean);
resultsChat.add(newMessage);
mChatAdapter.notifyDataSetChanged();
}
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private ArrayList<ChatObject> resultsChat = new ArrayList<ChatObject>();
private List<ChatObject> getDataSetChat() {
return resultsChat;
}
}
In FirebaseHelper Class I declare retrieve ArrayList method witch return spacecrafts ArrayList and it call fetchData method to add new Item in spacecrafts , In MainActivity I fill my adapter with helper.retrieve on the onCreate method , and make Dialog to add user Items when click saveBtn witch fill my adapter with helper.retrieve also , but adapter is fill with nothing , I make Toast to detect the problem and found that spacecrafts.size is fill every time with new Item but helper.retrieve().size every time =0 , Can anyone Shows me my mistake ?
here is FirebaseHelper Class :
class FirebaseHelper {
private DatabaseReference db;
private ArrayList<Spacecraft> spacecrafts=new ArrayList<>();
int x;
public FirebaseHelper(DatabaseReference db) {
this.db = db;
}
public Boolean save(Spacecraft spacecraft)
{
Boolean saved ;
if(spacecraft==null)
{
saved =false;
}else
{
try
{
db.child("Spacecraft").push().setValue(spacecraft);
saved =true;
}catch (DatabaseException e)
{
e.printStackTrace();
saved =false;
}
}
return saved;
}
private void fetchData(DataSnapshot dataSnapshot)
{
spacecrafts.clear();
for (DataSnapshot ds : dataSnapshot.getChildren())
{
Spacecraft spacecraft=ds.getValue(Spacecraft.class);
spacecrafts.add(spacecraft);
x=spacecrafts.size();
}
}
ArrayList<Spacecraft> retrieve()
{
db.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return spacecrafts;
}
}
and here is Main Activity class :
public class MainActivity extends AppCompatActivity {
DatabaseReference db;
FirebaseHelper helper;
MyAdapter adapter;
private RecyclerView rv;
EditText nameEditTxt,propTxt,descTxt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.content_main);
rv= (RecyclerView) findViewById(R.id.rv);
rv.setLayoutManager(new LinearLayoutManager(this));
db= FirebaseDatabase.getInstance().getReference();
helper=new FirebaseHelper(db);
adapter=new MyAdapter(this,helper.retrieve());
rv.setAdapter(adapter);
Toast.makeText(MainActivity.this, "helper.retrieve().size() = " + helper.retrieve().size(), Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, "spacecrafts.size() = " + helper.x, Toast.LENGTH_SHORT).show();
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
displayInputDialog();
Toast.makeText(MainActivity.this, "spacecrafts.size() = " + helper.x, Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, "helper.retrieve().size() = " + helper.retrieve().size(), Toast.LENGTH_SHORT).show();
}
});
}
private void displayInputDialog()
{
final Dialog d=new Dialog(this);
d.setTitle("Save To Firebase");
d.setContentView(R.layout.input_dialog);
nameEditTxt= (EditText) d.findViewById(R.id.nameEditText);
propTxt= (EditText) d.findViewById(R.id.propellantEditText);
descTxt= (EditText) d.findViewById(R.id.descEditText);
Button saveBtn= (Button) d.findViewById(R.id.saveBtn);
saveBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//GET DATA
String name=nameEditTxt.getText().toString();
String propellant=propTxt.getText().toString();
String desc=descTxt.getText().toString();
//SET DATA
Spacecraft s=new Spacecraft();
s.setName(name);
s.setPropellant(propellant);
s.setDescription(desc);
if(name.length() > 0)
{
if(helper.save(s))
{
nameEditTxt.setText("");
propTxt.setText("");
descTxt.setText("");
adapter=new MyAdapter(MainActivity.this,helper.retrieve());
Toast.makeText(MainActivity.this, "spacecrafts.size() = " + helper.x, Toast.LENGTH_SHORT).show();
Toast.makeText(MainActivity.this, "helper.retrieve().size() = " + helper.retrieve().size(), Toast.LENGTH_SHORT).show();
rv.setAdapter(adapter);
adapter.notifyDataSetChanged();
d.hide();
}
}else
{
Toast.makeText(MainActivity.this, "Name Must Not Be Empty", Toast.LENGTH_SHORT).show();
}
}
});
d.show();
}
}
Firebase operations are run asynchronously that means they are run on a separate thread, So your method ArrayList<Spacecraft> retrieve() returns the list before it is populated.
I try this and its work
private void fetchData(DataSnapshot dataSnapshot)
{
// spacecrafts.clear();
for (DataSnapshot ds : dataSnapshot.getChildren())
{
Spacecraft spacecraft=ds.getValue(Spacecraft.class);
spacecrafts.add(spacecraft);
x=spacecrafts.size();
}
}
ArrayList<Spacecraft> retrieve()
{
db.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
// try to clear spacecrafts here
spacecrafts.clear();
fetchData(dataSnapshot);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
// and here
spacecrafts.clear();
fetchData(dataSnapshot);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return spacecrafts;
}
}
I have this query in my Firebase
mDataBase = FirebaseDatabase.getInstance().getReference("animals);
query = mDataBase.orderByChild("height").limitToLast(20);
query.addChildEventListener(new AnimalsEventListener());
My listener
private class AnimalsEventListener implements ChildEventListener{
private AnimalsEventListener(){
}
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Animals details = dataSnapshot.getValue(Animals.class);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
}
How can I get the size of all animals that matched the query before working on dataSnapShot? sometimes they can be less than 20;
It's not possible to know children count using ChildEventListener, use ValueEventListener instead.
public class AnimalsEventListener implements ValueEventListener {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getChildrenCount() == 20) {
for (DataSnapshot dataSnapshotEntry : dataSnapshot.getChildren()) {
Animals details = dataSnapshotEntry.getValue(Animals.class);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
}
To attach this listener, use addValueEventListener() method
query.addValueEventListener(new AnimalsEventListener());
If you wanna use childEventListener i recommend u to use official FirebaseArray class.
To get the item count:
FirebaseArray mFirebaseArray = FirebaseArray(Query ref);
mFirebaseArray.getCount();