onPause onResume alternative? - android
I've got a bit of a dilemma and not quite sure how to solve it. Here's the scenario...
I have a multi activity application which plays music from the time it starts to the time the application exits.
However, if I use onPause / onResume to detect when the activity is sent to the background and pause the music in onPause and resume play in onResume, the music "skips" briefly when I start the next activity as the calling activity is finished once the startActivity() is called.
If I don't pause / resume the music in onPause / onResume the music plays smoothly but does NOT stop if the home key is pressed and the activity is sent to the back.
Is there a way to detect an activity is sent to the background (using, say a timer and application flag) without having to use onPause / onResume?
If this is not possible or too hard to implement (I'm still learning as we all are), is there a way to create an "invisible" launcher activity which runs in the background to handle such things but never seen?
As always, thanks in advance.
Turns out there's no simple way around this.
First thing you should do, is move your music streaming to a service, this way it doesn't depend on any activity.
Then you need to tell the service to stop when the entire application is in the background, not when one activity is paused. this fine answer suggests adding a timer to your application, and wait for a couple of seconds after an activity is paused. Of no other activity in the app is resumed - the app is assumed to be in the background.
I wouldn't add a timer to your application, but rather let your music playing service do this (notify the service in each onPause and onResume). Also, two seconds is too long for playing music, I'd start with 500ms and see if it's acceptable.
It's pretty simple IMHO
What you are trying to figure is if the new activity is from your application, continue playing the music, else stop.
You can do this with a boolean flag.
Here's the algorithm:
-boolean flag is set to true in onResume in all activities
-Keep the statements which pause the music in onPause
-Put the above statements (in onPause) in an if(boolean flag)
-whenever an event happens to start a new activity i.e. a button is clicked in your activities, etc, clear the flag (set it to false) in the event listener - eg: the button's onClickListener
This should work
The changeover between activities looks like this:
Activity A onPause
Activity B onCreate (or onRestart if it's already created)
Activity B onStart
Activity B onResume
Activity A onStop
You have a few options how to take advantage of this. You can subclass Application, and keep a boolean in the application class. Make a base Activity that does the following:
In onPause(), call the application to change the boolean to false.
In onResume(), call the application to change the boolean to true.
In onStop(), call the application to stop the music unless the boolean is set to true.
If all of your Activities extend this base Activity, then this will work. When A stops, as long as B was another one of your Activities, it will have resumed and set the boolean to true, so your music will keep playing.
There's a second approach that uses a Bound Service, where you bind in onStart() and unbind in onStop(). You can explore that on your own if you so desire.
You can (and in the fact should) use service to handle the music player. This is the component you are calling as "invisible activity".
If you start it by bindService() method in onResume and unbind in onPause() of each activity in your application it should run all the time. When no activity is bound to the running service the service is stopped by system, so all you need is just stop the music in the onDestroy() or in the onUnbind() method of the service.
Here you have a nice diagram of the Service lifecycle: http://www.tutorialspoint.com/android/android_services.htm
I'm not 100% if automatic management of servers lifecycle will be enough - in such case you can use startService() method to keep the service working all the time, when onUnbind of service is called put some delayed (i.e. using Handler.postDelayed(Runnable r) ) check if after i.e. after 1s service is still unbound and stopSelf() in such case.
OK, here's the solution and it's fairly straightforward once I thought about it in a more logical way.
What I have done is:-
Create a public static int called activityCount.
In the onCreate function of each activity I increment activityCount by 1.
I #Override public void finish() and decrement activityCount by one
and call super.finish().
In onPause if activityCount == 1, pause the music.
In onResume if activityCount == 1, play the music.
This is giving me the desired effect by continuously playing the music but when the home button is clicked the music stops and resumes when the activity is resumed.
Thanks for all the suggestions as it helped me think more logically.
Related
Android how to stop timer when app go to background
I know there are ton of questions as this have been asked in stackoverflow. Most of those suggest to implement onResume and onPause to control how the app behaves when it goes to background/foreground. But I couldn't actually use that method in my case. I have a timer that will run when my application start (or after user login). So it is not dependent on any activity in my app. What I want to do is to stop the timer (to save power resource) when app goes to background and restart it when app come back to foreground. By implementing onResume and onPause will stop and start the timer when user switch between the activities (because I implemented in all the activities), and this is not what I wanted. Please give advice how this to be done in better way.
You can use cancel() method in onPauso() so when the app are in background you stop the timmer In the method onResume() you launch other time your Timer. you can see method in: http://developer.android.com/reference/java/util/Timer.html
extend the Application class and add a public static counter on it. On every onPause() and OnResume(), increment or decrement it, when the counter is zero you app is in background.
Associate two activities with a service. Terminate the service if the application is put in the background
I have an activity A that starts a Music Service on a button click and optionally can start another activity B on another button click. I want the music to play in the background when the application is being used. When it is not being used (both Activity A and B are not visible) I would like the music to stop. I've tried starting the service from Activity A on the button click using startService(mMusicIntent) and stopping in a similar way using stopService(mMusicIntent). The music does, indeed, stay playing as I jump between A and B, however if I am in Activity B and I put the application into the background (Home or switch app) the background Music service still plays. I can only stop the service using the onDestroy() method in Activity A. Is there a better way of doing this? I don't want to pass data between either activities and the service (it simply plays music) so I didn't feel that binding was appropriate. But I could be wrong.
I ended up doing this with a bound service. I still don't know if this is best way to do something like this but it has the desired effect. Activity A binds to the MusicService on the button click. In the MusicService we set the bind to start playing the music. Activity A unbinds when either the button is reclicked or Activity A is stopped. Activity B binds onCreate() and unbinds when onStop(). For sure I could probably tweak the code so that the correct lifecycle pairs are selected but this works for my use case.
how to stop or finish activity from called service?
In my app I am required to Stop the activity(MyAct.java) when a service(BackgroundService.java) is called, and further i wish to continue this service(BackgroundService.java).please help?
Implement a started service, call startService(Intent service) in your activity(for instance, a button pressed) then call finish() immediately in your activity. Check out here to see how to create a long running background service, even without need a activity to start the service.
android: AlarmManager and activity life cycle
I decided to write simple alarm clock (using AlarmManager). When alarm works out I want to show simple dialog with 2 buttons: OK and Snooze. So I have a question: what should I connect with my Pending Intent? I mean Service, Activity or BroadcastReceiver? At present version I use BroadcastReceiver where I start Activity that shows the dialog. I start it with flag FLAG_ACTIVITY_NEW_TASK. In onStrat() method I start music service. When OK button's pressed I call finish() for activity and stop music. In OnPause() I call finish() also. I do it because if two alarms run simultaneously then according to activity life cycle method onPause() will be called. It works... but sometime the music starts for a few seconds then finishes....then start again and finishes and so on. Why? Thanks.
So I have a question: what should I connect with my Pending Intent? I mean Service, Activity or BroadcastReceiver? Probably an activity in this case. Theme your activity to look the way you want (e.g., Theme.Dialog) rather than fussing around with a regular dialog box. It works... but sometime the music starts for a few seconds then finishes....then start again and finishes and so on. Why? It is impossible to answer this question with the information you have supplied, sorry.
Stopping and starting a Service based on application state
I have a Service which tracks the location of the user. Currently, the Service boots when the application starts and stops when the application terminates. Unfortunately, if users keep the application in the background, the Service never stops and drains battery. I would like the Service to stop when my application is not in the foreground. I was hoping the Application class would let me Override onPause and onResume handlers, but it does not have them. Is there another way I can accomplish this?
I haven't tested this yet, but it looks like if you use Context#bindService() (instead of Context#startService()), the service should stop when no more activities are bound to it. (see Service lifecycle). Then use onPause()/onResume() in each activity to bind/unbind from the service. Alternatively, you could add a pair of methods on your service which tell it to start/stop listening for location updates and call it from each activity's onResume()/onPause(). The service would still be running, but the location updates wouldn't be draining the battery.
Reading all the above answers I would suggest Simply add a boolean global flag for each activity & put it in your onResume & onPause & also while launching an Activity Something like this public void onPause() { super.onPause(); activity1IsResumed = true; } &same for onResume & similarly when launching a new Activity startActivityForResult(myintent ,0); activity2IsResumed = true; activity1IsResumed = false; then in your Service simply check if(activity1IsResumed || activity2IsResumed || activity3IsResumed) { //your logic } else { //another logic //or dont run location tracker } & you are done!
You should override the onPause and onResume methods on your Activity. If you have multiple activities you may want to have a common base class for them and put the start/stop logic into the base class.
I have not tried this approach but I think you can override the home key of android device by using KeyEvent.KEYCODE_HOME and you can use stopService(Intent) to stop your service and when again application resumes, you can write startService(Intent) in the onResume() method of your Activity. This way I think your service will only stop when user explicitly presses home button to take application in the background and not when he switches from one activity to another.
What I would suggest is overriding the onPause/onReume methods as others have said. Without knowing more about the flow of your application and interactions between Activities, I can't give much more information beyond guesswork. If your Activities are persistent, however, my recommendation would be to utilize the Intents better when switching between Activities. For instance, each Activity should have a boolean "transition" flag. So, when you move from one Activity to the next, you set up an Intent extra: intent.putExtra("transition",true); Followed in the receiving Activity by: (in onCreate) intent.getBooleanExtra("transition",false); This way, for each Activity that launches, you can know whether it has come from another Activity, or if it has been launched from a home screen launcher. Thus, if it gets a true transition, then onPause should NOT stop the service--that means you will be returning to the previous Activity after it returns. If it receives no "transition" extra, or a false transition, then you can safely assume there is no Activity underneath it waiting to take over for the current one. On the first Activity, you will simply need to stop the service if you are switching to another Activity, which you should be able to figure out programmatically if one Activity is started from another.
It sounds like the real problem is how to only stop the service when you go to an activity that isn't one of your own? One way would be to in your onPause method to stop the activity. Do this for all your activities. Then override your startActivity method. And in here do a conditional test to confirm that you are purposefully navigating to one of your own. If your are set a flag to true. Now go back to your on pause overridden method. And only stop your service if the flag is not equal to true. Set the flag to false. All events that navigate away will close your service. Navigating to your own will leave it intact. Do the overriding in a base class that all your activities extend. Writeen in my andolroid. Will post ezaple later.
Try using the Bound Services technique to accomplish this. Bound Services | Android Developers You can use bound services in a way such that the service will stop when no activities are bound to it. This way, when the app is not in the foreground, the service will not be running. When the user brings the app back to the foreground, the Activity will bind to the service and the service will resume.
Create methods registerActivity() and unRegisterActivity() in your Application object and implement first method in all you acts onResume() and second in acts onPause(). First method add activity to List<Activity> instance in your app object, unRegisterActivity() checks size of list in every call if==0 stopService();.