Performance Issues with Boolean List of Data in Firebase - android

I have de-normalized data as suggested in the docs in firebase database. With a list of groups a user is a member of I am storing in the :value. However, with the use of this suggestion of using this list in FirebaseUI, while scrolling through a large list, attaching listeners is causing a performance bottleneck.
Is there any way listeners are not attached each time when user scrolls the list? Or any other way to reduce performance issues with a large list of booleans referencing another location in the database?

https://firebase.google.com/docs/database/android/retrieve-data#child-events
You should only have to attach one listener, child_changed
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);

Related

ChildEventListener must implement onChildChanged

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.

Stop getting Real Time update on Firebase Database Reference

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

Retrieving data from Firebase Android Studio

Structure of my Firebase Datebase looks like that:
I want to retrieve data from it in such a manner that when I change the value of the "Name" in database it will instantly change in Android Studio. Right now, I use .addChildEventListner method combined with Map<String, String>. Could someone help me ?
Edit: My code:
Firebase markerRef = myFirebaseRef.child("marker");
markerRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(com.firebase.client.DataSnapshot dataSnapshot, String s) {
Map<String, String> map = dataSnapshot.getValue(Map.class);
double latitude = Double.parseDouble(map.get("Lat"));
double longitude = Double.parseDouble(map.get("Lon"));
LatLng location = new LatLng(latitude, longitude);
String filename = map.get("Name");
String[] splitString = filename.split(",");
mMap.addMarker(new MarkerOptions()
.position(location)
.title(splitString[0])
.snippet(splitString[1])
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));
}
#Override
public void onChildChanged(com.firebase.client.DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(com.firebase.client.DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(com.firebase.client.DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
In your activity create empty HashMap
Hasmap<String, Marker> markers = new Hashmap<>();
Then in onChildAdded
Marker m = mMap.addMarker(new MarkerOptions()
.position(location)
.title(splitString[0])
.snippet(splitString[1])
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));
markers.add.put(dataSnapshot.getKey(), m);
And in onChildChanged
Marker m = markers.get(dataSnapshot.getKey());
m.setPosition(newLocation);
//And anything else, that changing
And finally in onChildRemoved
markers.get(dataSnapshot.getKey()).remove();
markers.remove(dataSnapshot.getKey());
Firebase data is retrieved by attaching an asynchronous listener to a FirebaseDatabase reference. The listener is triggered once for the initial state of the data and again anytime the data changes.
private DatabaseReference mDatabase;
mDatabase = FirebaseDatabase.getInstance().getReference();
To add a value event listener, use the addValueEventListener() or addListenerForSingleValueEvent() method. To add a child event listener, use the addChildEventListener() method.
You can use the onDataChange() method to read a static snapshot of the contents at a given path, as they existed at the time of the event. This method is triggered once when the listener is attached and again every time the data, including children, changes. The event callback is passed a snapshot containing all data at that location, including child data. If there is no data, the snapshot returned is null.
Example :-
ValueEventListener postListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
Post post = dataSnapshot.getValue(Post.class);
// ...
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
};
mPostReference.addValueEventListener(postListener);
Child events are triggered in response to specific operations that happen to the children of a node from an operation such as a new child added through the push() method or a child being updated through the updateChildren() method. Each of these together can be useful for listening to changes to a specific node in a database.
Example :-
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);
In some cases you may want a callback to be called once and then immediately removed, such as when initializing a UI element that you don't expect to change. You can use the addListenerForSingleValueEvent() method to simplify this scenario: it triggers once and then does not trigger again.
This is useful for data that only needs to be loaded once and isn't expected to change frequently or require active listening. For instance,
Example:-
final String userId = getUid();
mDatabase.child("users").child(userId).addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get user value
User user = dataSnapshot.getValue(User.class);
// ...
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "getUser:onCancelled", databaseError.toException());
}
});

firebase android having trouble retrieving a list of children at a specific location

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);

FireBase OnChildAdded not called on Android

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);
}
}

Categories

Resources