I'm new to firebase realtime database, and have a basic question I cannot seem to find the answer to.
I need my Android app to keep track of changes in the database, so I understand I need to use addValueEventListener, with the onDataChange method. However will the method onDataChange, be called even if the app is destroyed? I need to be able to access the changes of the information in the database even if the app isn't running in the background, (for example the user force quits the app). This is because when the values reach a certain point, I want to show a pop up notification, so I need to able to read the values even when the app isn't running.
If the onDataChange is called even when the app is in the background, will this drain battery use since the phone is always listening for changes.
Sorry for the basic question, but I couldn't find the info.
Thanks!
...when the app is dead, is the EventListener still listeneing, and will onDataChange be called?
Event listeners are only active while the context they run in is active. For listeners you attach in an activity, that means they're active while the app is running. Even then Android might kill the listeners (or more accurately: the socket they use for communicating with the server) if the user isn't actively using the app.
If you want the listener to stay active longer, you can indeed consider managing the listeners in a background service. But even there, Android might close the listener to preserve battery life. That is the one thing to always keep in mind: if your use-case interferes with the user's preference (and most users are likely strongly prefer longer battery life over any specific app feature), it's unlikely to continue working in the long run.
A better approach is to combine listeners with Firebase Cloud Messaging for sending messages. FCM messages are more likely (though still not guaranteed) to be delivered when the user is not actively using the app, and you can use them to run some code of your app when they arrive. You'll want to use FCM's data messages for this, which is how most app deliver background updates.
You can also use an FCM data message to just wake up your own code, then have that code attach a listener, and get its updates. This type of behavior is known as sending a tickle, since all the data message does is waking the application code up.
Related
I've just been reading about adding a service to my application, and since 7/8 there are now service restrictions to improve phone performance.
I've seen that the recommended approach is to use a job scheduler, but will that not just periodically start a new listener if I did that?
Basically I update my database, and using a snapshot listener I want to update my user in real time. When the app is closed, I'd like to send a notification.
My issues (if I'm correct) are that constantly making a new Firestore request will eat through my request allowance.
Also, if its a job scheduler it won't quite be real time?
I've read that you can use a foreground service, but this doesn't really seem like that task that needs a permanent notification and would annoy the user.
Anyone got any tips on how I'd implement this?
Thanks
Using a listener after an android application is closed
You can use a listener after an android application is closed, by not removing it. Once you are using a listener, you also need to remove it according to the life-cycle of your activity. But this will work only for a shot period of time because Android will stop your service if the app is not in the foreground. It does this to save resources when the app isn't being used. It also might stop your app from doing any networking, or even kill the app process completely. There's nothing you can do to prevent this, other than making it a foreground service, as you already mentioned.
A foreground service is probably not the best thing to do for your case, nor is it the best thing for your users. Read more about limitations on background services.
My recommendation is to use Firebase Cloud Messaging to notify your app when something has changed that it might be interested in. So your users will recieve notification even if they will keep their app closed.
I am creating an android app which has a chat feature. I would like to create a notification if a new message arrives when the chat is not open. My messages are stored in a firebase database. I see two options for creating these notifications. One is to use the firebase function to trigger a firebase cloud message. The other is to use an Intent Service which runs an onChildAdded Event handler. The Intent Service seems much easier to me. Am I missing something? What would be a good reason to use Cloud Messaging over an Intent Service with the event handler running?
If you're worried your Service will keep running all the time (and draining your battery), then that's a good reason to use the cloud function. Moreover, there are chances are that your service might get killed.
Because only a few processes are generally
visible to the user, this means that the service should not be killed
except in low memory conditions. However, since the user is not
directly aware of a background service, in that state it is considered
a valid candidate to kill, and you should be prepared for this to
happen. In particular, long-running services will be increasingly
likely to kill and are guaranteed to be killed (and restarted if
appropriate) if they remain started long enough.
Finally, all the fuss you'd have to go through to deliver the results to an activity might be as painful as developing a cloud function.
In the company I work we decided to use the cloud function and it was pretty easy. We only needed to keep track of the FCM token of the devices and our function would monitor a certain node in our Real Time database. Every time somebody wrote there we'd get warned and would be able to act on it (grab the node, identify sender and receiver and with the saved FCM token send the notifications). We've used this tutorial to achieve what we wanted. Some links on how to write the cloud function, here, here and a So question that I also used here. The official docs too.
I have written an android app that uses firebase anonymous authentication and writes to the firebase database from a foreground service. I am using onDisconnect().removeValue() to cleanup data created by my app when the websocket is closed. When a user is actively engaging with the app, the onDisconnect() call triggers as expected (meaning my security rules are OK). However, when the foreground service is left running for a long period of time (e.g. overnight, screen turns off, etc.), the onDisconnect() call is never triggered again. The app continues to function upon wakeup (communicating with firebase server, etc.) but when it comes time to close the app (following a period of idle time), it seems that the onDisconnect() call has been lost somehow.
I have read that anonymous authentication sessions are quietly refreshed by the firebase SDK every hour. Is it possible this is happening in the activity (and being killed by the OS, but keeping the foreground service alive), therefore causing the server to discard the callback to onDisconnect? If so, can this functionality be preserved within the foreground service?
Firebase has had a bug recently (not sure if it's been fixed), where when it reauthenticates every hour, it loses the onDisconnect() because it no longer has permission to alter that node. This then causes the duplicate.
Some possible solutions:
Attach a timestamp and check if the last timestamp is over an hour, and if it is, then delete it when adding the new one.
Remove authentication requirements for writing in the node to keep track of the disconnects (this would not be secure though, depends on your needs).
Here are some more alternatives, and a better explanation of the problem from a member of the Firebase team: here.
Android application processes can live indefinitely. When the user stops using an app, Android may continue to keep the process alive, in order to make it load faster if and when the user comes back. You can think of this is an optimization, and you should expect this to happen sometimes. You shouldn't try to control this behavior - let Android manage this for you.
Your connection to the database is not being closed because the app is still alive and holding on to its connection to the database. I suggest you track for yourself when the user stops using your app, and force a cleanup at an appropriate time after that, without assuming that Android will ever kill your app's process.
If the call Crashlytics.start(this) is on Application's onCreate() method, will it count an active user if something wakes up my application process?
For e.g. if I have a broadcast receiver or alarm, will it count as an active user if those wake up the app?
Thanks
I'd say that it does not count, but my answer is purely based on logic and common sense.
Crashlytics' recommended approach is to initialize the SDK in your Application class, so that crash logs (and every other type of info) can be collected as soon as possible in your app's lifecycle. When they introduced the Answers panel, my guess is that they figured out their way of determining what an active user is, based on a series of parameters and actions that indicates that the user is actually operating the app (which is, by the way, differs in every Analytics SDK provider, e.g. Google Analytics).
In short, I don't think that the Crashlytics.start() method immediately counts for an active user, because that would be just nonsense. But there's a quick way of determining that:
Create a testbed application that is fired up when you send a specific broadcast message
Initialize the SDK in the Application's onCreate() method
Using adb, send the broadcast message and meanwhile keep an eye on the Answers page of Crashlytics
Wait for some time (it may take some time to register the hit): is the user being tracked as active?
You can try to reach Crashlytics support for this, but I'm not sure they are going to give away this information.
EDIT
Adding some evidence I've found here:
A session begins when the app enters the foreground and ends once the app is backgrounded for 30 seconds or longer.
This leads to believe (as I wrote above) that their way of detecting an active user does not rely purely on the SDK initialization.
I guess that it should, unless it has a more complicated logic of some "actual activity" instead of just opening the app. Application.onCreate() is being called on the beginning of any Activity, Service or Broadcast of your app.
This is what is written in android documentation:
Called when the application is starting, before any activity, service,
or receiver objects (excluding content providers) have been created.
Implementations should be as quick as possible (for example using lazy
initialization of state) since the time spent in this function
directly impacts the performance of starting the first activity,
service, or receiver in a process. If you override this method, be
sure to call super.onCreate().
But keep in mind that if the app is already running the Application.onCreate will not re-run as it is already created.
I have been given multiple solutions to what I thought would be a common scenario. Unfortunately, none seem to work as expected.
I have created a pretty simple android game. The users can invite friends to play and there are a few activities they are routed through during the game lifecycle. All turns and data is stored in a remote server which is exposing the data through web services. Every time an invitation is sent, or the opponents complete their turn, the user is prompted via the service to play their turn.
The service prompts the user using a standard android notification telling them it's their turn. I don't want the service to poll the web service or present notifications while the user is viewing the game (they'll already know if it's there turn).
I have tried the following solutions without any success.
Start the service in the onPause method of the main activity and stop the service in the onResume method of the main activity.
Problem - Each time the user leaves the activity for another one the service starts. The user may be writing something or creating an invitation and they are prompted to take their turn.
Bind each activity to the service and set a boolean (running) flag in the same onPause/onResume methods of all activities.
Problem - This seems logical, but for some reason the service never presents a notification. This is likely user-error, but I'm not sure this is the correct solution anyway.
Start the service in the onPause method of all activities and stop the service in the onResume method of all activities.
Problem - Based on the toasts I'm presenting on the screen showing the state of the service this works as expected. The problem is the user is presented with notifications while the service is off. Apparently my toasts are misleading.
Any help is greatly appreciated. Sample code is not necessary, but would be appreciated if the solution is any more complex than the concept described above.
Thank you.
Don't use a service, use the Google Cloud Messaging and in the receiver of the broadcast, check the state of the game and then decide whether or not to show the notification. Polling is generally bad, uses data and battery unnecessarily.