How can i implement a listener on firebase to keep check if data has changed in firebase? for example, a user insert a data in firebase, a second user is checking a listview of that data, i want to refresh that listview automatically.
You need to listen to Firebase Database changes, and once data added to the database, you will be notified on client side and you will receive the data that is added to firebase database because it's realtime database.
mFirebaseDatabase.child("yourNode").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
// here you need to handle the value added.
}
#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) {
}
});
There are two ways.
Way 1: If possible, create a callback and after user insert a new item, you callback will fire.
Way 2: Every N second (2-5), you could make a request to server to ask him if new data avaliable.
Also if you are building a list with recyclerView, for efficient updating list, use DiffUtil.
Which case is better, you decide. I don't work with firebase list.
Related
On application start the ChildEventListener is getting fired the amount of child present in the firebase database. For instance, if I have already 3 children present in the database, the listener will get invoke 3 times when I start my application. s I have defined the code for the listener in my service class and I am starting the service from my Splash class.
From SplashScreen.class
startService(new Intent(this , BackgroundService.class));
From BackgroundService.class
listenToJob() method, is in onStartCommand() method of Service
private void listenToJob (){
String collectionName = "rideRequest";
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference(collectionName);
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot snapshot, #Nullable String previousChildName) {
Toast.makeText(BackgroundService.this, "Hey, new child is added.", Toast.LENGTH_SHORT).show();
OnChildCreated(snapshot);
}
#Override
public void onChildChanged(#NonNull DataSnapshot snapshot, #Nullable String previousChildName) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot snapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot snapshot, #Nullable String previousChildName) {
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
};
myRef.addChildEventListener(childEventListener);
}
I don't what cause this behavior. Isn't onChildAdded() method should only be invoked when a new child is added to the database? I have 3 children already present in the database and when I open my app this onChildAdded() method is getting invoke 3 times.
I want this method to fire up only when child is added to the database!
According to the Firebase documentation on listening for child events, the onChildAdded:
is triggered once for each existing child and then again every time a new child is added to the specified path.
So what you're seeing is the expected behavior.
If you want to only be informed of new children, you need to have something that defines when a child is "new". For example, if you're using Firebase's built-in push() method to generate the child nodes, you can use the keys that generates to only get child nodes that are generated after you start listening with:
String key = myRef.push().getKey()
myRef.orderByKey().startAt(key).addChildEventListener(childEventListener);
here is my function to get data :
public void retrievedata(){
FirstRef.child(obj.getsEventID()).orderByChild("date").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s)
{
if (dataSnapshot.exists())
{
DisplayMessages(dataSnapshot);
}
}
#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) {
}
});
}
private void DisplayMessages(DataSnapshot dataSnapshot) {
Iterator iterator = dataSnapshot.getChildren().iterator();
String Article = (String) ((DataSnapshot) iterator.next()).getValue();
String Key = (String) ((DataSnapshot) iterator.next()).getValue();
String Organisateur = (String) dataSnapshot.child("name").getValue().toString();
String date = (String) dataSnapshot.child("date").getValue().toString();
Date resultdate = new Date(Long.parseLong(date));
String date2 = DateFormat.format(resultdate).toString();
ListOfArticles.add(0,new ListItemTypeOne(Key, Article, Organisateur, date2));
adapter.notifyDataSetChanged();
}
Let's suppose I have 10 articles, they are kept in the disk memory thanks to :
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
Now, while I was offline someone added 2 more articles which makes 12.
If I go online, and execute the function "retrieve data", will it simply call the onchildadded with the 10 child in the memory and the 2 new child from the firebase database or will it download all of the 12 childs from firebase ?
When you attach a listener for data that is already present on the device, Firebase immediately satisfies the listener with the data that it has on the device.
So the Firebase client will immediately call your onChildAdded with the 10 child nodes that we persisted earlier.
It then sends a request to the server to get the most up to date version. It does this with a so-called delta-sync, meaning that it by sending a hash value of the local state, which the server compares to the current state in the database. The server then sends the delta back, which the Firebase client then uses to update its internal snapshot and the state on disk.
If there are any changes, the Firebase client then fires the correct local events to allow your application to update to the new state. So in the case where two child nodes were added, it will call onChildAdded for each of those.
If you were to use a listener with a limit, say limitToLast(10), then the Firebase client would also call onChildRemoved for the two children that are no longer within that query (since they were pushed out by the new children).
The previously cached 10 children will be loaded from disk and not transferred from the server again.
everyone! I want to delete the value from Firebase Database using RecyclerView.
However, I cannot find the key of a child, which I want to delete.
Firstly, I add data to the database like this:
String key = MainActivity.databaseReference.push().getKey();
MainActivity.databaseReference.child(key).setValue(myAppModel);
In terms of deleting, in my RecyclerView adapter i have written onClickListener to ImageView and delete item from list successfully!
In addition, i tried many ways of how to delete this item from database as well, but the data still untouched.
Here is the code:
holder.appDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mAppModelList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mAppModelList.size());
final ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
dataSnapshot.getValue(AppModel.class);
MainActivity.databaseReference.child(mAuth.getUid()).child(dataSnapshot.getRef().getKey()).removeValue();
System.out.println(dataSnapshot.getRef().getKey()); // it gives me user id...but in my MainActivity it gives the real key
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
MainActivity.databaseReference.addListenerForSingleValueEvent(eventListener);
}
});
As i mentioned in code comment, getRef().getKey() gives me the Firebase user id, like mAuth.getUid()
And in MainActivity i receive the real name(key) of child
Query query = databaseReference;
query.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
AppModel appModel = dataSnapshot.getValue(AppModel.class);
appModelResult.add(0, appModel);
AddAppDialog.setAppModelResult(appModelResult);
System.out.println(dataSnapshot.getRef().getKey());
reloadFragment(fragment);
}
What i should do to delete the data from database?
Thanks everyone in advance!
Solved it!
Initially, when I want to delete item I wrote
MainActivity.databaseReference.child(mAuth.getUid()).child(appModel.getAppId()).removeValue();
However, as i noticed, you should not write user id
MainActivity.databaseReference.child(appModel.getAppId()).removeValue();
And here we are!
Hope, it could help everyone
I know that when we retrieve data from Firebase ,it will be asynchronous, so ussally i will put all the code inside addChildEventListener, like example i want to sort userList below. But i am confused, if the List is really big, like million Users, so it means the method sortUser(user) will be called million times ? Can anyone explain this to me, I'm new to firebase
myRef.child("User").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
User user= dataSnapshot.getValue(User.class);
userList.add(user);
sortUser(userList);
}
#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) {
}
});
You currently use a ChildEventListener, which means your onChildAdded gets called for each child node immediately and then later whenever a new child is added. This indeed can be a lot of invocations.
If you use a ValueEventListener, its onDataChange will only be called once for the initial data (no matter how many child nodes there are), and then once for each change.
By adding a ValueEventListener to your current set up, you can keep things simple: add the child nodes to the lit like you're already doing, but only sort in onDataChange.
myRef.child("User").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
sortUser(userList);
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
};
Firebase will only synchronize the data for the User node once, even when you have two listeners on it.
You should probably retrieve the data sorted server side by using order-by methods and then listen to that one.
var userRef = firebase.database().ref('posts').orderByChild('Users');
If I guess correctly, you would not need separate sorting client side.
You can also filter data. Do refer the docs
is there any ways to read data from Firebase once the Activity is loaded. At this moment I am using the regular valueEventListener, but in order for it to work, there has to be some sort of a change in the database
mDatabaseReference.child("Users").child(mUser.getUid()).
child("Posts").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
arrayOfQuestionForms.clear();
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
QuestionForm tempQuestionForm = postSnapshot.getValue(QuestionForm.class);
arrayOfQuestionForms.add(tempQuestionForm);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
What I am looking for is some way to read data from Firebase without using listeners. I have looked at other similar posts but I don't think there is a clear answer for this yet.
There is no way for reading data from a Firebase database without using listeners. Everything is about listeners when it comes to Firebase. It's true that when setting a value, we just need to use a method named setValue() directly on the reference. Unfortunately, there is no method within Firebase, let' say getValue(), which acts in the same way as setValue().
To solve this, i recommend you using addListenerForSingleValueEvent.
Add a listener for a single change in the data at this location. This listener will be triggered once with the value of the data at the location.
in order for it to work, there has to be some sort of a change in the database
This is not true and a common source of confusion for developers.
With your current code, Firebase will immediately start reading the data from the server. Once it gets that data, it invokes your onDataChange().
From the documentation:
This method is triggered once when the listener is attached and again every time the data, including children, changes.
for such purpose I used different kind of listener - ChildEventListener. It has different #Override methods. The method onChildAdded returns every child-nodes of the node when called first time (i.e. on activity start).
Put attention - maybe you will need to slightly change the reference to DB (trim back one hierarchy level), to point to the parent node. If you expanded snapshot of your DB structure, I can look.
Here is updated code (sorry is made any typo - I couldn't test it as have no your DB :)
mDatabaseReference.child("Users").child(mUser.getUid()).child("Posts").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
arrayOfQuestionForms.clear();
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
QuestionForm tempQuestionForm = postSnapshot.getValue(QuestionForm.class);
arrayOfQuestionForms.add(tempQuestionForm);
}
}
#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) {
}
});