Android -- How to properly handle onPause/onResume methods? - android

I have an app that starts playing sounds and begins/resumes gameplay in the onResume() method, but what I'm noticing is that if my app was the last run application when I put the phone into standby (screen off), and I just press the Menu button to check the time, then the phone starts playing the game and sounds in the background (the app isn't actually visible, only the screen with the date/time is, yet onResume must have been called in my app). What am I to do here? Is there a way to discern what is reactivating the app, and then add a conditional statement that only starts the game when the app is actually visible?
Here is a snippet from my onResume:
#Override
protected void onResume()
{
mySaveGame = Utilities.loadSavegame(this);
//check the savegame
if(mySaveGame!=null)
{
//start game using savegame values
this.startFromSavedGame(mySaveGame.getIsLevelComplete());
}
else
{
//run the 1st-run components
this.startFirstRun();
}
super.onResume();
}
The only thing I can think of doing to prevent the game from starting whenever the screen gets turned on (even when the app isn't visible) is to put this.finish() as the last line in onPause()... but that forces you to restart the app every time you want to go back to it because the precess itself was killed (which is fine because my onPause saves persistent data, but it's not an elegant solution).
Please help.

Have you considered switching to onStart() and onStop(), rather than onResume() and onPause()?

I was having the same problem (I had my music player resume/pause at onResume()/onPause()) and the best solution I found is to pause and resume my activity when it is on the foreground which you can get with public void onWindowFocusChanged (boolean hasFocus) callback.
Edit: This in an old and slightly incorrect answer - correct response is described in the Android Developers Blog: making android games that play nice

Related

Back Button is not Resulting in onDestroy for Android 12

I have just started insuring my apps work with Android 12. What I notice is that for (I believe) all of them when the back button is pressed, then onPause() is called, but not onDestroy(). This means the app is still running.
Previously, onDestroy() was called after onPause() when the back button was pressed.
It is a definite problem for ones running a background service that has (actually, must have) a notification. Stopping the service is typically done in onDestroy() and certainly not in onPause(). Since onDestroy() is not called, the service continues running and the notification remains up. If you select the notification, it brings up the [running] app again. There is no way to stop the service and hence the notification, except by killing the process via the overview (left) button.
I also notice that if an app with a service crashes, then the notification stays up. This is surely not desired behavior.
You can, and apparently have to, kill the process with the overiew (left) soft button).
I can get around this by implementing onBackPressed:
#Override
public void onBackPressed() {
// This seems to be necessary with Android 12
// Otherwise onDestroy is not called
Log.d(TAG, this.getClass().getSimpleName() + ": onBackPressed");
finish();
super.onBackPressed();
}
but that seems like a kludge.
For other apps maybe it doesn't matter they are still running or not. However, it is unexpected behavior.
Added later: This is apparently intentional and is a change from previous behavior. It is mentioned in this article (curtesy of #ianhanniballake):
https://developer.android.com/about/versions/12/behavior-changes-all#back-press
I have several apps, and I have verified it is happening with all of them on Android 12. It is causing problems with those that have services.
The implied question for this issue is what to do about it. I personally am implementing onBackPressed for those and leaving the others be.
I am not sure if this should be an answer or a comment, so, given the size of the text, I decided to go with answer.
The solution I came up with was forcing onDestroy() to be called, by finishing the activity from within onStop() in some circumstances.
In my case, I use onDestroy() to persist a few things. I know there are better ways of doing this, but that is how the code was, and this quick workaround fixed the issue, at least temporarily:
#Override
protected void onStop() {
// Try to differentiate a home button press from the screen being turned off
final PowerManager powerManager = (PowerManager)getSystemService(POWER_SERVICE);
if (powerManager != null && powerManager.isInteractive()) {
if (webViewHost != null && !webViewHost.isPaused()) {
// My old/existing logic (for Android < 12)
finish();
} else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
// New workaround for Android 12 onwards
finish();
}
}
super.onStop();
}
This is the project's repo, already pointing at the line where the workaround has been created.
As per the new changes in Android 12, back button on root/home activity is now minimize the app instead of close entirely. Hence it calls only onPause() and onStop() functions not onDestroy(). So I called finish() function from inside onBackPressed() function like this.
override fun onBackPressed() {
super.onBackPressed()
finish()
}
This could be a simple and quick workaround to match the behaviour with below Android 12. However the good practice is to optimise the app as per the Android 12 guidelines mentioned here

Dealing with Android's MediaPlayer while rotating screen, pressing Home Button or App is interrupted

I'm in a tricky part of the workflow/design on my app.
I have a MediaPlayer that runs into a Service. I want the music to stop when user leaves (BUT NOT CLOSES) the App. That is, the Home Button.
So I implemented MediaPlayer's pause() and start() methods into Activity's onStop() and onResume(), respectively. That is working fine when testing with the button and relauching the App, but it also happens when the screen is rotated due to the Activity's lifecycle.
So, how can I avoid this in a efficient / elegant way? The music mustn't be interrupted when device is rotated. I thought in overriding Home Button's click method, pause there the MediaPlayer and setting a global boolean flag to check in onResume() if MediaPlayer must be resumed. But this seems to me like a hack or so, not a good practice.
I'm wrong with this? Is there a better way?
Any advice is appreciated.
There are a few options here:
If your minSdkVersion is at least 14, you can check the isChangingConfigurations() flag before stopping the media player:
#Override
protected void onStop() {
if (!isChangingConfigurations()) {
// Stop the Media Player
}
}
Otherwise, you could watch for onUserLeaveHint():
#Override
protected void onUserLeaveHint() {
// Stop the Media Player
}
Although that won't be called if another application is forcibly drawn to the foreground (e.g. a phone call comes in).
EDIT: As an alternative you might be able to rely on onWindowFocusChanged(). It is called with false when leaving the activity with Home or Back, but not on a configuration change. It should also be called when another activity is brought to front.
#Override
public void onWindowFocusChanged(boolean hasFocus) {
// Stop the MediaPlayer
}
As a side note, you should typically use symmetric lifecycle methods (e.g. instead of onPause(), onStart() use either onPause()/onResume() or onStop()/onStart())

Pausing the Activity in Android

I have developed a game in android and it has some timer in it,when ever I'm playing the game if some one rings me the game is not going to paused state the time is still running in the background.what i need is when some in coming call has arived it should display a prompt message that the game is in pause state how to achieve this..?
You will have to override the onPause() function which is called everytime you get called you go back to the main menu or whatever. Here is a sample of the docs :
When the system calls onPause() for your activity, it technically means your activity is still partially visible, but most often is an indication that the user is leaving the activity and it will soon enter the Stopped state.
I advise you to read this link carefully to understand the different steps in an activity life and that link as well
Here is how to override your onPause() function :
#Override
protected void onPause() {
//Do something like pausing the timer
}
When the user goes back to the game, you want the timer to restart and therefore, you'll override the onResume() function :
#Override
protected void onResume() {
//Resume the timer
}
Have a good day !

Android stopping background music service on with multiple activities

I have an app that has a service that plays music. This is working because the service just keeps on going (and thus playing).
However, when the user presses the home key in any activity I should be able to detect if my application is idle or not. I've been looking around and every question I find has an asnwer like: "use the onPause() or onStop()" but that only works for one activity and copying the code to every activity seems like a dirty solution.
In my main I have tried:
onDestroy: doesn't work when home key pressed.
onPause: stops the music even when starting another intent (not intended).
I have considered detecting the current activity from main but that's a way too dirty solution.
In my main activity I start my service (backgroundMusicPlayer):
#Override
protected void onCreate(Bundle savedInstanceState) {
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
setContentView(R.layout.activity_main);
else
setContentView(R.layout.activity_main_landscape);
//_________BRON(MediaPlayer): http://stackoverflow.com/questions/3369068/android-play-sound-on-button-click-null-pointer-exception
backgroundMusicPlayer = new Intent(MainActivity.this, BackgroundMusicPlayer.class);
startService(backgroundMusicPlayer);
mp = MediaPlayer.create(MainActivity.this, R.raw.buttonclick); //knopgeluiden laden
super.onCreate(savedInstanceState);
}
What should I do?
What you need to know is when your activity is in the background (and when it has returned). There are a few ways to do this, but a reliable way I found was based on this answer.
It works on the premise that using a time reference between activity transitions will most likely provide adequate evidence that an app has been "backgrounded" or not.
This has worked for me and in the callback you can reliably tell your service to do whatever you want.
Also, if your App goes to the background and you're playing, you should then startForeground in your service (so it gains priority) and when the app returns, just stopForeground.
That way you avoid having a foreground service all the time, even when the user is interacting with the app.

Managing background download : Android

I'm designing a news app where I need to download fresh articles and their detailed stories whenever user opens my app. I'm doing all of this a background thread. My prime focus was that the background thread should stop as soon as user exits the app so as to prevent user for incurring extra download charges.
To achieve this, I initiate background download in my splash screen and I keep on checking for flag variable that lets the background process know if the app is still running.
Now my question is: I'm very clear about initialization of this flag variable. I've initialized it in onCreate() of Application subclass since it is the point where application starts. But I've no idea where to clear it. I tried doing it in onDestroy() of my MainActivity. However, I found that onDestroy() is often called on transition between one activity to another if system needs to free memory. So, doing so there would stop my background thread even when I'm switching across screens and not actually closing the app. How should I deal with this scenario ? Is there a smarter way of handling this ?
I don't think you have to do that : either the user is pressing the "Home" button (which most people do) and then it's common for apps to keep running in background, and as so to still be easily accessible to the user in the state they left it. Either you provide a "close app" button which really kills the app, which will also kill every kind of thread created by the app and you don't have to worry.
If you really want, you could capture the "Home" clicks, and use those to kill the app before returning to home, which is a nice thing to do if your app has 0 initialization time.
But I've no idea where to clear it. I tried doing it in onDestroy() of my MainActivity.
In order to know if the activity is destroyed because the user finished it (with Back) or Android will re-create it, you could use isFinishing();
Something like:
protected void onDestroy() {
super.onDestroy();
if(isFinishing()) {
// stop the news feed download
}
}
Or better, stop the feed download in finish():
public void finish() {
// stop the news feed download
super.finish();
}
To go back to what you said above with:
I'm very clear about initialization of this flag variable. I've initialized it in onCreate() of Application subclass since it is the point where application starts.
Even if the activity is finished, the application is very probable to still live. The Android OS will decide when to kill it. So you will initialize the download once the app starts, then you will stop it on onDestroy() or on finish() within Activity, depending on your desire, but if the application doesn't stop (most probable) and you're re-entering again in the news activity you should be starting the news download.
I would rather initiate the download in the background in onCreate(Bundle savedInstance), but when savedInstance is null (so I know this is the first create of this activity) and stop it (if hasn't stopped already by itself) in finish();
Hope it helps!
To begin with for downloading datas from webservice (json or xml) you should use AsyncTask (easy to use)
so what i mean was, to clear your flag with ondestroy(), for when the application is exited, and maybe you can catch when the home button is pressed
Override the below method in your Activity,
#Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);
}
And now handle the key event like this,
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_HOME)
{
//do something
}
if(keyCode==KeyEvent.KEYCODE_BACK)
{
//do something
finish();
}
return false;
}

Categories

Resources