问题
I'm trying to setup an Android Service in my app that listens for new Childs in a Firebase Ref, and throws a Notification when that happens.
I'm having issues because addChildEventListener onChildAdded apparently is called one time for every existent record and only then actually listens for new childs..
In this answer @kato states that if addChildEventListener is called like ref.endAt().limit(1).addChildEventListener(...) it would get only the newly added records.
It actually only gets one record at a time (I suppose with limit(1)) but it still gets an existant record before listening for added records.
Here's some code:
Initializing the Listener in onCreate():
@Override
public void onCreate() {
super.onCreate();
this.handler = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
AllowedGroup ag = dataSnapshot.getValue(AllowedGroup.class);
postNotif("Group Added!", ag.getName());
}
...rest of needed overrides, not used...
I'm using the AllowedGroup.class to store the records, and postNotif to build and post the notification. This part is working as intended.
Then, onStartCommand():
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
this.f = new Firebase(FIREBASE_URL).child("users").child(this.currentUserUid).child("allowedGroups");
f.endAt().limit(1).addChildEventListener(handler);
return START_STICKY;
}
It still returns one existant record before actually listening for newly added childs.
I've also tried querying by timestamp, like so:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
this.f = new Firebase(FIREBASE_URL).child("users").child(this.currentUserUid).child("allowedGroups");
f.startAt(System.currentTimeMillis()).addChildEventListener(handler);
return START_STICKY;
}
Hoping that it would only get records set after the service was started. It doesn't get existant records, but doesn't even get newly added childs.
EDIT:
I've also thought of something like getting into memory first all of the existant records, and conditionally post a notification if the record brought by onChildAdded does not exist on the previously gathered list, but that seems a bit like overkill, and thought that could be an easier (more API-friendly) way of doing this, am I right ?
Can anyone provide me with some insight on this ? I can't really find anything on the official docs or in any StackOverflow question or tutorial.
Thanks.
回答1:
If you have a field modifiedOn, you can index that and setup a query like:
Query byModified = firebaseEndpoint.orderByChild("modifiedOn").startAt(lastInAppTime);
回答2:
For me the logic was is to have value -"status" for example- which needs to be validated before deciding whether it is really new or was an old record then I set the "status" to a different value so I don't get it next time:
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildKey) {
if(dataSnapshot.hasChildren()) {
String Id = (String) dataSnapshot.child("user_id").getValue();
String status = (String) dataSnapshot.child("status").getValue();
if (Id != null && Id.equals(storedId) && status != null && status.equals("created")) {
Log.d("INCOMING_REQUEST", "This is for you!");
sessionsRef.child(dataSnapshot.getKey()).child("status").setValue("received");
}
}
}
回答3:
I overcome this problem by keeping items of firebase database reference node in a List; and whenever onChildAdded(...) method is triggered, check if the incoming datasnapshot is in your list or not; if not, then it's new data
In order to achieve this you must meet below conditions:
- Have a unique value that must not repeated from item to item. (this can be easily achieved when you add items into Firebase using
.push()method. - Override
.equals()method of your model class in order to fulfill the comparison based on this unique value.
Here code snippets based on your inputs
Model class
public class AllowedGroup {
private String id;
public static List<AllowedGroup> sGroups;
// reset of fields ...
public AllowedGroup() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public boolean equals(@Nullable Object o) {
// If the object is compared with itself then return true
if (o == this) {
return true;
}
// Check if o is an instance of AllowedGroup or not
if (!(o instanceof AllowedGroup)) {
return false;
}
// typecast o to AllowedGroup so that we can compare data members
AllowedGroup group = (AllowedGroup) o;
// Compare data based on the unique id
return (group.id).equals(id);
}
}
Listening to firebase added nodes
@Override
public void onCreate() {
super.onCreate();
this.handler = new ChildEventListener() {
@Override
public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
AllowedGroup group = dataSnapshot.getValue(AllowedGroup.class);
if (!AllowedGroup.sGroups.contains(group)) {
// Here you'll receive only the new added values
}
}
// ...rest of needed overrides, not used...
}
}
来源:https://stackoverflow.com/questions/24713765/firebase-android-notifications-childadded-how-to-get-only-new-childs