I'm using OnChildAdded event for get all data from database on Android.
The first time and many time later, It works well.
But something, onChildAdded don't be call for old child anymore.
Uninstall and install app again make it work again.
I checked permission and added event.
I don't know what's wrong and what have to do to fix it.
This code, I use for init
prayersRef = database.child("prayers");
Log.w(TAG, "FireBaseDatabaseManager");
prayersListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Prayer prayer = dataSnapshot.getValue(Prayer.class);
prayer.uid = dataSnapshot.getKey();
Log.w(TAG, "onChildAdded:" + prayer.uid);
if (delegate != null) {
delegate.OnPrayerAdded(prayer);
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.w(TAG, "onChildChanged:" + dataSnapshot.getKey());
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.w(TAG, "onChildRemoved:" + dataSnapshot.getKey());
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.w(TAG, "onChildMoved:" + dataSnapshot.getKey());
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "onCancelled", databaseError.toException());
}
};
Then I add event in here
Log.i(TAG, "Add Child Event Listener");
prayersRef.addChildEventListener(prayersListener);
OnChildAdded event is used to refreshing data. Try to retrieve data using ListenerForSingleValueEvent :) then in onDataChange you can put all downloaded items in list :) like:
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Model> models = new ArrayList<>();
for(DataSnapshot snapshot : dataSnapshot.getChildren()) {
Model model = snapshot.getValue(Model.class);
models.add(model);
}
}
Related
This is driving me insane. I'm using "onChildAdded" and if I switch it to "onChildChanged" then it asks me to switch back to "onChildAdded". I have no idea why it's doing this.
Here's my code:
Query queryRecycler = mDatabase.limitToLast(5);
queryRecycler.addChildEventListener(new ChildEventListener() {
public void onChildAdded(DataSnapshot dataSnapshot, String previousKey) {
messageList.add(dataSnapshot.getValue(Message.class));
mMessageAdapter.notifyDataSetChanged();
}
});
And the complete error:
Class 'Anonymous class derived from ChildEventListener' must either be
declared abstract or implement abstract method
'onChildChanged(DataSnapshot, String)' in 'ChildEventListener'
If you want to implement ChildEventListener, you should override onChildAdded,onChildChanged, onChildRemoved, onChildMoved. even you do not want it. (Code example from firebase)
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
// A new comment has been added, add it to the displayed list
Comment comment = dataSnapshot.getValue(Comment.class);
// ...
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
// A comment has changed, use the key to determine if we are displaying this
// comment and if so displayed the changed comment.
Comment newComment = dataSnapshot.getValue(Comment.class);
String commentKey = dataSnapshot.getKey();
// ...
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());
// A comment has changed, use the key to determine if we are displaying this
// comment and if so remove it.
String commentKey = dataSnapshot.getKey();
// ...
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
// A comment has changed position, use the key to determine if we are
// displaying this comment and if so move it.
Comment movedComment = dataSnapshot.getValue(Comment.class);
String commentKey = dataSnapshot.getKey();
// ...
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "postComments:onCancelled", databaseError.toException());
Toast.makeText(mContext, "Failed to load comments.",
Toast.LENGTH_SHORT).show();
}
};
ref.addChildEventListener(childEventListener);
You might want to add an #Override annotation to the implemented method .onChildChanged(), else it won't be recognized as the implementation of the abstract method. The documentation reads:
Indicates that a method declaration is intended to override a method declaration in a supertype.
I know firebase database is a real time database but for my feature I don't want to update a specific database reference (below reference) value in real time. So, is there any way to stop getting real time update on firebase database reference?
mUserDataRef = FirebaseDatabase.getInstance().getReference().child("users");
The code you shared only creates a reference to a location in the database. It does not start getting realtime updates yet. To start getting realtime update, attach a listener with addValueEventListener or addChildEventListener. An example of the latter:
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "onCancelled", databaseError.toException());
}
};
mUserDataRef.addChildEventListener(childEventListener);
This will receive data updates until the listener it removed. To remove the listener, call:
mUserDataRef.removeEventListener(childEventListener);
If you only want to get data once, instead of receiving continuous updates, you can call addListenerForSingleValueEvent:
mUserDataRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
Log.d(TAG, "onDataChange:" + dataSnapshot.getKey());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "onCancelled", databaseError.toException());
}
});
I highly recommend studying these two pages in the Firebase documentation:
Read and write data on Android
Work with lists of data
Below I've attached the picture of DB Structure and I'm trying to get the list of child nodes from firebase DB reference (timingInformation). How can I get the list?
To read/synchronize data from the Firebase Database, you'll need to attach a listener. A simple case:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("timingInformation");
ref.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "onCancelled", databaseError.toException());
}
};
For more see the Firebase documentation on loading data from a list, and the reference documentation on what you can do with a snapshot.
After create data on Firebase. I try retrieving data from Firebase. But I have problem, I think may be Log.d(TAG,list.size()) run before ref.addChildEventListener(childEventListener); complete. Who can help me ?
public class NewFirebase extends AppCompatActivity {
List < Product > list = new ArrayList < > ();
private static final String TAG = "Firebase";
DatabaseReference ref;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Firebase.setAndroidContext(this);
ref = FirebaseDatabase.getInstance().getReference();
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
// A new comment has been added, add it to the displayed list
Product comment = dataSnapshot.getValue(Product.class);
for (DataSnapshot child: dataSnapshot.getChildren()) {
Product post = child.getValue(Product.class);
list.add(post);
}
// ...
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "postComments:onCancelled", databaseError.toException());
}
};
ref.addChildEventListener(childEventListener);
Log.d(TAG, list.size() + "");
}
class RetrievingData extends AsyncTask < Void, Void, Void > {
#Override
protected Void doInBackground(Void...voids) {
return null;
}
}
}
You need to take a second approach to how you are structuring your code, or even take a look at the definition of callback/listener itself.
The addChildEventListener() method assigns a callback and initiates a query for retrieving the result. That is, of course, done in background.
Using listeners will never work that way, that's why they were made for, to don't follow line-by-line execution. If you want to get some result from them, you need to put the code inside their methods, which is when they give you some response. Can take milliseconds, seconds, even minutes, but don't expect to be so immediate to be quicker than the execution of the next line that it was posted to execution.
Take a look at https://www.firebase.com/docs/android/guide/retrieving-data.html.
If you want to see the size of the list that you get from Firebase database, you should use addValueEventListener instead of addChildEventListener
List<Product> commentList = new ArrayList<>();
myRef.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot postSnapshot: snapshot.getChildren()) {
Product comment = postSnapshot.getValue(Product.class);
commentList.add(comment);
}
// here you can print the size of your list
Log.d(TAG,list.size())
}
public void onCancelled(FirebaseError firebaseError) {
System.out.println("The read failed: " + firebaseError.getMessage());
}
});
I am trying to retrieve a list of children at a specific location, but I get only gibberish when I do what I think is right.
My code for retrieving data:
final String userId = FirebaseAuth.getInstance().getCurrentUser().getUid();
mDatabase = FirebaseDatabase.getInstance().getReference();
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
adapter.add(dataSnapshot.child(userId).getChildren().toString());
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
adapter.add(dataSnapshot.child(userId).getChildren().toString());
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());
adapter.add(dataSnapshot.child(userId).getChildren().toString());
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "postComments:onCancelled", databaseError.toException());
Toast.makeText(getActivity(), "Failed to load entries.",
Toast.LENGTH_SHORT).show();
}
};
mDatabase.addChildEventListener(childEventListener);
Screenshot of datastructure
What I am trying to retrieve a list of the children below the userId.
What am I doing wrong?
I don't think you should add the ChildEventListener to the root node of your firebase database since this would download all the data in your database.
Instead, call it on the specific user since you only want it for that UID.
final String userId = FirebaseAuth.getInstance().getCurrentUser().getUid();
mDatabase = FirebaseDatabase.getInstance().getReference(userId);
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
// maybe use a POJO here to collect data easily
// the toString() method is maybe for testing??
adapter.add(dataSnapshot.getValue().toString());
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
// This part should have appropriate code
// Unless of course you actually want to add it
//to the adapter everytime
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
// This part should have appropriate code
// Unless of course you actually want to add it
//to the adapter everytime
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "postComments:onCancelled", databaseError.toException());
Toast.makeText(getActivity(), "Failed to load entries.",
Toast.LENGTH_SHORT).show();
}
};
mDatabase.addChildEventListener(childEventListener);