I've read and re-read the documentation but I'm still now sure if using a service (and how) is the right way to keep a timer running.
I basically want to have a countdown timer, but I want it to run uninterrupted even if the app gets closed (and show up as an ongoing notification). When a certain activity in the app gets opened (resumed, opened, launched from clicking on the notification), I want it to be able to get the current value from the timer (no more frequent than once per second). If the app got closed, I still want the timer to be able to use/launch activities or other services (or access the database) of my app.
So if I understood the Android developer docs correctly, I should use a service that is started (because when started it should be able to do its thing even in the app gets closed) and bound (so an activity can get data from it). Then I searched Stack Overflow for similar topics and some people are recommending using IntentService (but can it send data to an activity?), or Handlers or even AlarmManager.
I'm really confused and I'd prefer to be able to pick the right approach from the start (rather than finish the app and then realize my approach wastes a lot of battery or something). The problem with documentation is it answers questions it thinks I have, so I have to ask a real person.
My suggestion is:
When user starts your timer save current system timestamp.
In your UI: Every N milliseconds just read saved value and compare it to current timestamp. This give you a diff = elapsed time.
You do not need any timer/service/alarm manager. Every time user has return to your app you just do step №2 to show elapsed time.
Related
Hello I am developing an application where I required to find time spent by user on a certain app like Facebook.
Whenever user has spent x minutes then I want to give some reward to user. Is there any good approach to achieve this in Android ?
As noted in the question Detect When other Application opened or Launched, you cannot listen for other applications launch signals, but you could sample the list of open applications every so often to check if the app you are looking for is a) running and b) in the foreground.
You would have to run this application as a service in the background, and I'm pretty sure that it could have devastating implications on the user's phone battery life.
You'll need a background Service that will check the phone's activity (applications in foreground) and count their active/foreground elapsed time.
List foreground applications
<uses-permission android:name="android.permission.GET_TASKS" />
You can detect currently foreground application with ActivityManager.getRunningAppProcesses().
It will return a list of RunningAppProcessInfo records.
To determine which application is on foreground check RunningAppProcessInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND.
How much time has been spent on it
Process.getElapsedCpuTime() is the best to go IMHO.
Unfortunately I don't know how to get the Process of another application...
So you could have a looping Service incrementing spent time everytime an application is on foreground, but that would not be super precise I'm afraid.
Another way would be to control yourself the opening of those apps and when they leave it and come back to yours, evaluate the spent time in foreground at that moment.
Just some thoughts, I don't have a complete answer, sorry.
I would like to notify my users of new content available in the latest version of my android game without using an external service like Push Notifications.
What I would like to do as a first step to achieve this is to just create a standard notification on application update.
This brings me to my question: is it possible to start a service the first time a user launches the game and then just keep it running indefinitely? I want to even keep it running after an update completes. Since it is possible that the code for the service may have changed between versions, would I need to stop the old version of the service manually and start the new version? Is it possible to even do something like this where the event that drives initiation of the service is the completion of an app upate?
My plan is to have this service check some persisted data about the last time the user was notified about new content and based on this I will be able to determine if a notification should be created for them after they update.
It's important that they are not required to go back into the game after update in order for the notification to be created. This is the problem that I am having now. Auto-updates occur and they don't know and hence also don't know that there are new stages, etc, available so they never go back into the game if they were already done with the previously available content.
It seems that games like Family Guy have got this approach working, but I am not sure if they implemented it in this way. Even after I update it, I will still get notifications even if I have not actually executed the app since update.
Services are mostly killed when other process needs the resources. Therefore use
startForground(...)
for running Services indefintly on background.
See here: http://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification)
What you can do is use the AlarmManager in your service that notifies you at certain time. Start the service, do the task and set again an alarm to notify you. In this way, you'll be able to run your service infinitely at periodic time.
I started redacting this answer on GameDev Stack Exchange before you
deleted the question. Unlike the guy who told you to delete, i thought it was an interesting question even for game dev stack exchange.
What you describe is a bad practice on android. I don't believe any game do that. What's more, android require "service" app to run as ForegroundService (This force you to display you app icon in the notification bar, so that users are always aware of running services) It can also be randomly be killed when the system lacks memory. However it can be implemented nicely using Alarms and AlarmManager.
Services and Notifications :
You can however schedule intents when the app is running, with AlarmManager, this is the good practice. Let's take a simple exemple : Candy Crush.
In Candy Crush, when you lose your last life, every 30 minutes you regain one, and have a limit of 5 lives. You want to notify the user when all his lives are back. How to do that ?
Exemple 1 :
When the user lose his last life or quit the game, schedule an intent with AlarmManager in (5-number_of_life)*30 minutes that will fire a local notification.
Exemple 2 :
Schedule an intent with AlarmManager every 30 minutes to check the number of lives, and fire a notification when the user have 5 lives again.
Using a Boot receiver may also allow you to schedule things as soon as the device boot.
However, users expects to be able to disable this kind of features.
Updates :
If you want your app to notify users when an update is available, you'll need to somehow check on the internet with a request on your server. You may schedule an intent again with alarm manager to check regularly if the update is available. If the user is ingame, you can also check it more regularly.
A lot of "online" games do that, and simply force the user to download the new update from the Play Store, before they can play again.
I have an App where the user can create multiple countdown alarms. Each one has it's own name, time to count, ringtone, etc.
I extended the CountDownTimer to hold each alarm setup and created a Singleton manager to manage all the alarms.
Everything is working fine until I leave the App.
The counters don't actually die. They have a weird behavior. After starting a counter:
1) if I press back key until the home screen and then power off the screen the alarm will trigger as it should.
2) if I press the home button then turn off the screen it will trigger only if I open the app.
3) if I just turn off the screen while still on the app it will trigger as soon as I turn on the screen.
I expected trouble because for that kind of thing I need to use Services, Handlers or other stuff like these.
The problem is, I'm new to Android and after reading a lot about it, I couldn't find a solution.
As far as I understood I should use Services, but it can have only one instance. How would I work with multiple alarms?
Is there other way of doing it?
I need a way to start each alarm and tell the system to keep counting no matter what happens! (and to call an Activity when it finishes)
Any help?
Is there other way of doing it?
If your goal is to alert the user of events in the future, regardless of whether your app is running, dump all your CountdownTimer logic, and switch to AlarmManager. It is specifically designed for this sort of scenario. You can set up an AlarmManager event for each timer, to get control when the end time is reached.
Also note that you will need to maintain information about your registered events in a file or database:
so users can add and remove them, and
so you can set up AlarmManager again if the user reboots their device
and to call an Activity when it finishes
Users may reject your app for that behavior. Not everyone wants to be interrupted in the middle of what they are doing with their device. Please allow this to be configurable, so the user can opt for something less intrusive, like a Notification.
You should replace your CountdownTimers with AlarmManager (as in CommonsWare's answer), after setting it up it will trigger your function to execute on specified time, here is official guide:
http://developer.android.com/training/scheduling/alarms.html
Soon you will find that after device reboot your alarms are lost, you need to restart them by catching android.intent.action.BOOT_COMPLETED broadcast.
Also you should not do a lot of work in your alarm onReceive, you should pass information to some other component like IntentService, to make it safe while device is asleep you should use WakeLock (sample project).
[edit] ---- you should also store your alarm/ringtone related data in some persistant storage, you can use for it shared preferences, or (more work) sqlite database.
I you really want to use timer (i.e. when you want to show countdowns on screen):
You don't have to have multiple timers to show multiple countdowns.
Everything you have to do is just put the target time into some collection, or event put it into the View.setTag().
Then you have timer (let say 1s tick) - on every single tick you have to iterate over all your gauges, check the target time and current time, parse the number and adjust the gauge.
However - as the timers works on separate (non main) threads - you will have to use handler or something like that.
If you want to just set some alarms - take the CommonsWare's answer - it's good one.
I'm looking for some timer alternative, since timer dies with app, is limited, and every timer launches own thread.
Sometimes I need to launch about 20-30 timers.
I need to set some event, in time, and when it comes display app screen. Is it possible?
This may or may not be possible depending upon your definition of "dies with app".
You can use AlarmManager to schedule PendingIntents to be invoked at specific times in the future. Those PendingIntents can launch activities. This will work if your app "dies" from ordinary causes.
However:
If the user force-closes your app via Settings, your alarms are unscheduled, and there is nothing you can do to stop this (nor do you have any alternative to AlarmManager that somehow survives this)
Please allow the user to determine whether or not you display an activity or raise a Notification at these times, as users may not necessarily appreciate having their game, navigation, video, or phone call interrupted by your activity.
You should use AlarmManager.
As CommonsWare says that there are some limitation of it, but that is ok, if an user force closes your application it means he doesn't want to use your application (any more or due to sort of memory)....
And I have a solution (but may be not the best), because you can not listen if user force closes your app, so one way is that you can re schedule your event on each start of your application. I know this is not a good solution but ..... we have no any other way yet
Here is a good example.
In my Android app, I have some data that needs to be synced daily but also needs to be updated every hour when a user is inside the app.
I have already implemented a service that gets called from an alarm for the daily update. Im having a problem with developing a strategy to do the hourly sync. I could use an hourly alarm too and fire the same intent, but since your app can be killed at any time, there would be no way to cancel it (and since they use the same Intent, doing a cancel would cancel ALL alarms including my daily sync, so that's probably not good).
The other option is to use a Timer that's set when inside the app, and have that fire my Intent when inside the app. Im assuming all Timers get cancelled when an app is killed right? But my app consists of several activities and I want the timer to work across all activities, how do I do that? I dont want to duplicate code - we're already using a subclass for Activity and ListActivity.
I have some data that needs to be
synced daily but also needs to be
updated every hour when a user is
inside the app.
The solution seems easy: drop the second requirement. Few apps are used continuously for hours on end, since people tend to use their Android phones for other things (e.g., phones), so your update-hourly-if-used-all-the-time code will probably never run.
I could use an hourly alarm too and
fire the same intent, but since your
app can be killed at any time, there
would be no way to cancel it
FWIW, your app will not be killed while it is on-screen. And, while it is not on-screen, you don't want the updates going hourly.
Im assuming all Timers get cancelled
when an app is killed right?
Apps generally are not "killed". We expect you to clean up after yourself when your activities are called with onDestroy(). If you set up the Timer with a daemon thread, you will need to terminate that thread.
But my app consists of several
activities and I want the timer to
work across all activities, how do I
do that?
Bind to your service from each of your activities. If it is started by your alarm Intent, have it do normal update processing. If it is started due to a binding request, just have it make sure its hourly Timer is running. When it is called with onDestroy() (e.g., after all activities have unbound), have it stop the Timer.
You might be able to have a Timer run in a background service (which get killed less than activities) but there is still no guarantee that Android won't kill your service either. And running something like this is the background might use a lot of battery.
What about doing the hourly sync in a background thread that get's created in onResume? And just save the last time the user did the sync, and if it has been > an hour just do the sync. Because I don't think there is any reason to eagerly sync data that the user is never going to see.