Is there a way to count number of children in firebase database? - android

mImageLike.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
mProcessLike = true;
//mLikeCount.setText("numLikes");
mDatabaseLike.addValueEventListener(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
if(mProcessLike)
{
if(dataSnapshot.child(post_key).hasChild(mAuth.getCurrentUser().getUid()))
{
mDatabaseLike.child(post_key).child(mAuth.getCurrentUser().getUid()).removeValue();
numLike--;
mProcessLike = false;
}
else
{
mDatabaseLike.child(post_key).child(mAuth.getCurrentUser().getUid()).setValue("Liked");
mProcessLike = false;
}
}
}
#Override
public void onCancelled(DatabaseError databaseError)
{
}
});
mDatabaseLike.addChildEventListener(new ChildEventListener()
{
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s)
{
numLike = dataSnapshot.getChildrenCount();
mDatabaseLike.child(post_key).child("numLike").setValue(numLike);
}
#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)
{
}
});
}
});
I was struggling with increasing count when like button is pressed and store that count number into the database "Like". I have declared DatabaseReference mDatabaseLike and it looks like this.
I am trying to count the number of children in each like(the ones with "Liked" string) and store them into each key(ex. Kb6cSLImN_7lrPyAr2Q) as numLike. When I click like button, it updates the count, but when I click the button again to remove that like, the number doesn't decrease.
Please help!. Thank you very much.

You should remove the ChildEventListener from the onClickListener so you're always keeping track of the Likes. You're also never decreasing the like count, you're just changing it locally. You have to set the value once you decrease it like this: mDatabaseLike.child(post_key).child('numLike').setValue(numLike);
I'd also recommend not keeping track of likes like that, and use Transactions instead. It will deal with conditions where two users click Like at the same time. With your current implementation, if two users click it at the same time, one like would overwrite the other and only increase by one rather than by two.

Related

RecyclerView swipe to add older Firebase Data

I am facing a problem with adding older data to RecyclerView with SwipeRefreshLayout so, here is how i retrieve from Firebase and put data into RecyclerView
private void messageList() {
referenceMessages.orderByKey().limitToLast(10).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
MessagesInfo messages = dataSnapshot.getValue(MessagesInfo.class);
result.add(messages);
adapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
MessagesInfo messages = dataSnapshot.getValue(MessagesInfo.class);
result.remove(messages);
adapter.notifyDataSetChanged();
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
as you can i see, I set limit of retrieved messages to last 10, what means the 10 newest messages will be displayed. So far everything works great, the messages are displayed like that
-20thmessage(the oldest)-
-21stmessage-
-...-
-29thmessage-
-30thmessage(the newest)-
now i use SwipeRefreshLayout like that
private void swipe(){
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
referenceMessages.orderByKey().endAt("-LHUhkub4iaZNNzmtUcs").limitToLast(10).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
MessagesInfo messages = dataSnapshot.getValue(MessagesInfo.class);
recyclerView.scrollToPosition(0);
result.add(0, messages);
adapter.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) {
}
});
}
});
}
and it retrieves data properly, i mean previous 10 messages before hardcoded endAt() but after swiping places data not properly. If i dont use index 0
new data is placed at the botoom of latest message and it looks like that
-30thmessage(the newest)-
-10thmessage-
-...-
-19thmessage-
-20thmessage(the newest)-
and when i use index 0 data is added from the top of already loaded messages but like that
-20thmessage(the oldest)-
-19thmessage-
-...-
-11ththmessage-
-10th-
so it is added upside-down. Hope you understand me :) any inputs are highly appreciated
You might try clearing the list first and then add the new messages.
Android SwipeRefreshLayoutBasic

Delete data from firebase in recyclerview using childeventlistener

I am trying to delete an image and some data from firebase and remove these from my recyclerview.
I have successfully managed to accomplish this and it's deleting the image allright, but it's not instantly deleting the image in the interface.
I have to leave the activity and return in order to view the updated view.
this is my ChildEventListener:
mDBListener = mDatabaseRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
mUploads.clear();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
Upload upload = postSnapshot.getValue(Upload.class);
upload.setKey(postSnapshot.getKey());
mUploads.add(upload);
}
mAdapter.notifyDataSetChanged();
mProgressCircle.setVisibility(View.INVISIBLE);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
mAdapter.notifyDataSetChanged();
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
what happens when i press delete:
#Override
public void onDeleteClick(int position) {
final Upload selectedITem = mUploads.get(position);
final String selectedKey = selectedITem.getKey();
Log.d(TAG, "SelectedKEY" + selectedKey);
StorageReference imageref = mStorage.getReferenceFromUrl(selectedITem.getImageUrl());
imageref.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if(user != null) {
Intent intent = getIntent();
Bundle bd = intent.getExtras();
String selectedId = (String) bd.get("selectedId");
mDatabaseRef.child(selectedId).child(selectedKey).removeValue();
Toast.makeText(ImagesActivity.this, "Item deleted ", Toast.LENGTH_SHORT).show();
}
}
});
}
and the onDestroy override:
#Override
protected void onDestroy() {
super.onDestroy();
mDatabaseRef.removeEventListener(mDBListener);
}
}
UPDATED TRY FOR SOLUTION
I tried for a solution and got a little bit closer to my goal.
Now when I delete an item in the view, and call for a Toast in my onChildRemoved, I get the toast. This is the code:
DatabaseReference mDatabaseRefff = FirebaseDatabase.getInstance().getReference(Uid).child(selectedId).child(selectedId).child(key);
dbEvent = mDatabaseRefff.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Toast.makeText(ImagesActivity.this, "Item deleted ", Toast.LENGTH_SHORT).show();
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
so basically I did not remove the old childeventlistener (Because it worked perfectly as it was supposed to work for everything else)
And now i put this childEventlistener below the first one, only now I am listening on the same child as I am trying to remove.
Now when I delete an item from the view, I get the Toast "Item deleted".
The problem is that when I add mAdapter.notifyDataSetChanged();
It still only shows the toast and nothing else happens...
I believe you need to Override onChildRemoved, remove the item from the adapter and call notifyDataSetChanged() to refresh the recyclerView.
onChildRemoved() Listen for items being removed from a list. The DataSnapshot passed to
the event callback contains the data for the removed child.
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
//add logic to remove item from adapter
String key = dataSnapshot.getKey();
//mAdapter.remove(index);
mAdapter.notifyDataSetChanged();
}
Following the update on the question, the next thing to do is simply update the Adapter, you detect what was removed from the database through the onChildRemove() and remove that from your adapter. Once you remove from the adapter, you simply call notifyDataSetChanged() and should work.
More info about Firebase Listen for child events
I didn't manage to find a solution in the childEventListener method. So I used valueEventListener instead and solved the issue.

Controling the occurrence of onChildAdded event in firebase database

I am working on android app in which I want to store unique IDs of users in firebase database, so to achieve this I have created a root, named "Users" and will store all the users unique IDs in this root.
So in order to check uniqueness I have to go through each child of "Users" and after checking the uniqueness I will add the uniqueID to "Users" root or will notify the user that uniqueId is not available.
When I check uniqueness, it's conditionals (if/else) execute before occurrence of OnChildAdded event, How to execute some code(mentioned in my code) after occurrence of OnChildAdded event
My Code
postBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(!uniqueIdText.getText().toString().trim().equals("")) {
uniqueness = true;
users.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (dataSnapshot.getKey().equals(uniqueIdText.getText().toString().trim()))
uniqueness = false;
}
#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) {
}
});
}
else if(uniqueIdText.getText().toString().trim().equals("") )
Toast.makeText(LoginActivity.this,"Please enter id",Toast.LENGTH_LONG).show();
//======================How to execute it(code below) after occurrence of OnChildAdded event====================
if (uniqueness){
DatabaseReference usersInfo = users.child(uniqueIdText.getText().toString().trim());
startActivity(new Intent(LoginActivity.this, MainActivity.class));
}
else{
if(!uniqueIdText.getText().toString().trim().equals(""))
Toast.makeText(LoginActivity.this, "ID not available, Please enter a new one", Toast.LENGTH_SHORT).show();
}
}
});
There is no way to know when all the onChildAdded events have been called. But you can know when the first data from the database has been synchronized by using a ValueEventListener.
But in this case, I'd highly recommend taking a different approach. Downloading all UIDs to check if one value is present is incredibly inefficient and won't scale. Instead, attach a listener to the specific UID that you're looking for. If that value exists, you'll get the value. If it doesn't exist, you'll get an empty snapshot:
users.child(uniqueIdText.getText().toString()).addSingleValueEventListener(#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
uniqueness = false;
}
else {
uniqueness = true;
}
...
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "onCancelled", databaseError.toException());
// ...
}
};

How to increase count and store into firebase database by clicking a button?

mImageLike.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
mProcessLike = true;
//mLikeCount.setText("numLikes");
mDatabaseLike.addValueEventListener(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
if(mProcessLike)
{
if(dataSnapshot.child(post_key).hasChild(mAuth.getCurrentUser().getUid()))
{
mDatabaseLike.child(post_key).child(mAuth.getCurrentUser().getUid()).removeValue();
numLike--;
mProcessLike = false;
}
else
{
mDatabaseLike.child(post_key).child(mAuth.getCurrentUser().getUid()).setValue("Liked");
mProcessLike = false;
}
}
}
#Override
public void onCancelled(DatabaseError databaseError)
{
}
});
mDatabaseLike.addChildEventListener(new ChildEventListener()
{
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s)
{
numLike = dataSnapshot.getChildrenCount();
mDatabaseLike.child(post_key).child("numLike").setValue(numLike);
}
#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)
{
}
});
}
});
Hi, thanks for reading. I am new to Android and Firebase and I was struggling with increasing count when like button is pressed and store that count number into the database "Like". I have declared DatabaseReference mDatabaseLike and it looks like this.
I am trying to count the number of children in each like(the ones with "Liked" string) and store them into each key(ex. Kb6cSLImN_7lrPyAr2Q) as numLike. When I click like button, it updates the count, but when I click the button again to remove that like, the number doesn't decrease.
Please help!. Thank you very much.

Firebase: Retrieving data sorted by child value

My structure is like following
- Posts
- keu23jndf
- dateTime:"2376464"
- name:"abc"
- key34njf
- dateTime:"4333434"
- name:"xyz"
Now, I want to retrieve sorted data by dateTime in descending order.
Thanks
Ok so first of all I would suggest you to not use a client sided timestamp but instead use the ServerValue.TIMESTAMP. In most cases this is going to be the better setup. If you know what you are doing and you want it exactly like that, forget this and just read on.
The problem if you want to sort from newest to oldest is that Firebase does (as far as I know) not support this.
A workaround would be to use the negative value of the Firebase ServerValue.TIMESTAMP.
This is how I do it. It may not be the perfect or right way, but it does work
private void prepareUpload() {
//mDatabase is a reference to the root of the Firebase Database
final DatabaseReference timestampReference = mDatabase.child("timestamp");
final String timestampKey = timestampReference.push().getKey();
timestampReference.child(timestampKey).setValue(ServerValue.TIMESTAMP);
timestampReference.child(timestampKey).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() != null) {
Long timestamp = 0 - Long.parseLong(dataSnapshot.getValue().toString());
upload(/*Starting upload with new timestamp here (this is just a dummy method)*/);
timestampReference.child(timestampKey).removeValue();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, databaseError.getMessage());
}
});
}
Now you have to set your Firebase Database rules as follows:
"Posts": {
".indexOn" : "date",
...
}
Finally you just have to query your 'Posts' somehow like this:
mDatabase.child("Posts").orderByChild("dateTime").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
//Do stuff with your data
}
#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) {
}
});
Hope this helps!

Categories

Resources