0

I want to send a notification whenever the data in firebase changes. But when I use addValueEvenListener() method it returns more than once. After that I tried using addListenerForSingleValueEvent() method but it now returns 2 times, When I start the app and when the data changes. Is there a way for it to return only one time which is when the data changes and not when the app starts?

Here is my code for now:

databaseReference.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                sendNotification("notification","App name",getIntent().getStringExtra("storeid"));
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {

            }
        });

EDIT: Just so every one understand my question. When I start the app, a notification is sent because of the code above. And I don't want this to happen, Instead I need to only send the notification when the data changes.

zyngot
  • 275
  • 1
  • 4
  • 19
  • you have to put an identifier created at and whenever you get calls always use the latest time data. Put some query which will help your to sort https://firebase.google.com/docs/reference/android/com/google/firebase/database/Query#addValueEventListener(com.google.firebase.database.ValueEventListener) – Ankit Aman Dec 27 '20 at 14:54
  • 1
    When you use `addListenerForSingleValueEvent` its `onDataChange` should only be called once. Can you show the code that reproduces the problem where it gets called twice? – Frank van Puffelen Dec 27 '20 at 15:10
  • @FrankvanPuffelen The same as the above but instead of addValueEventListener() I used addListenerForSingleValueEvent() – zyngot Dec 27 '20 at 18:19
  • In that case the `onDataChange` will be called at most once per call to `addListenerForSingleValueEvent`. I've never seen Firebase do this wrong, so I highly recommend checking if you don't call `addListenerForSingleValueEvent` multiple times. – Frank van Puffelen Dec 27 '20 at 19:39
  • @FrankvanPuffelen Will it be called when the app starts though? – zyngot Jan 02 '21 at 13:11
  • " Is there a way for it to return only one time which is when the data changes and not when the app starts?" See https://stackoverflow.com/questions/33885059/how-to-only-get-new-data-without-existing-data-from-a-firebase – Frank van Puffelen Jan 02 '21 at 15:30
  • @FrankvanPuffelen This is javascript and not java – zyngot Jan 09 '21 at 19:02
  • @FrankvanPuffelen Even if it was java this is a very different question – zyngot Jan 09 '21 at 19:03
  • Even though the syntax may be different the API works the same across platforms. Instead of just saying *that* this is a very different question, you might want to elaborate *why/how* it is different. Your latest edit helps for that. There is no way to tell Firebase to not give you the current data, but only give you changes. That's simply not how the API works. The common way to solve this is to add a timestamp to each node, so that you can use a query to indicate from which moment you want to get data back. That's what David's answer to the question I linked explains. – Frank van Puffelen Jan 09 '21 at 19:50
  • For Android, see my answer here: https://stackoverflow.com/questions/34745248/firebase-onchildadded-for-new-data – Frank van Puffelen Jan 09 '21 at 19:52

3 Answers3

1

According to the Docs, the ValueEventListener returns a Value not just when the data is changed but also when the method is first executed.

As far as I can tell, there are two possible solutions to your problem:

  1. You use a background service in order to keep the method running in the background so that it does not return a value for each time you open the app. This would also mean, that you would get notifications when the app is not even open. I don't know if that is in your interest.

  2. Store the value and check it manually each time. You can save the returned value to the storage and check if the new value is different from the prior value each time the listener executes.

I hope I could help, happy coding

Emil
  • 140
  • 1
  • 8
  • The first solution contains the answer to another question I was going to ask later so thanks for that! But if I use a background service for the notification does that mean that even if the app is killed it returns the notification? Another point to keep in mind it that the value event listener is in another activity not the first one. so every time the user goes to the activity a notification appears. I will check the second one though, thanks! – zyngot Dec 27 '20 at 14:59
  • @VarroxSystems any background service will be killed when an app is forcefully stopped in the settings but apart from that, it keeps running when the application is left and/or closed by the user, so that should not be a problem as most people don't force stop apps. To create such a service, use [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager) – Emil Jan 02 '21 at 18:04
1

Let's say you have one boolean variable declared globally in the class where you register the listener

boolean isCalled=false;

Reset it just before registering the listener.

    isCalled=false;
    databaseReference.addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot snapshot) {
                 if(isCalled){
                      //it is already called once.
                      sendNotification("notification","App name",getIntent().getStringExtra("storeid"));
                   }else{
                      //called first time
                      isCalled=true;
                   }
                }
    
                @Override
                public void onCancelled(@NonNull DatabaseError error) {
    
                }
            });
rahat
  • 1,840
  • 11
  • 24
  • Great answer! needs a little more explanation though. I have no idea how I haven't thought of that. – zyngot Jan 09 '21 at 21:34
  • Well, Please let me know what things should be explained to make the answer more clear. :-) – rahat Jan 10 '21 at 09:41
0

Data stored in the Firebase Realtime Database is retrieved by attaching it to an asynchronous listener data source. The listener is triggered again once for its initial state and each time its data changes. In your case, no clear solution is presented in the documentation.

Arda Kazancı
  • 8,341
  • 4
  • 28
  • 50
  • Thanks for the info, but does this mean I can not achieve what I am trying to do? Because I think there might be an option, I just can't find it. – zyngot Dec 27 '20 at 14:28
  • I think it runs at least 1 time for the initial state of the data. – Arda Kazancı Dec 27 '20 at 14:37