It was my understanding, obviously wrong, that onPause() is called whenever the back button is pressed? Now in my code I've put this onPause() event:
#Override
protected void onPause(){
super.onPause();
if(!_END_GAME){
Builder _alert = new AlertDialog.Builder(this)
.setMessage("onPause, with game NOT over!");
_alert.setNeutralButton("OK.",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
arg0.dismiss(); // Kills the interface
System.runFinalizersOnExit(true);
finish();
}
});
_alert.setTitle("Your Score!");
_alert.show();
}
}
Now the problem is, the dialog does not launch what-so-ever, and then the code errors out. I put the dialog there to try to visualize where the onPause() was called and help me debug some other variables and such. Yet like I said it never even gets shown. Any ideas why this would be? Is there a function that is launched prior to onPause() when the back button is pressed? Thank you in advance for any info.
onPause will always be called when your activity is no longer in the foreground, that's guaranteed. Maybe your _END_GAME is not false? Add a debug log output to your onPause method, you'll see that it always gets called.
I should note though that displaying a dialog during onPause is extremely bad form - the user is trying to get rid of your app (could even be because of an incoming phone call). You DO NOT want a dialog then. That goes against the Android design.
In fact, the Android OS will simply short-circuit your app if you try to do lengthy shenanigans in onDestroy or onPause. Basically, if those get called, you're supposed to disappear quietly.
If you really want to intercept the back button, you can check for the button like Ted suggested, but keep in mind that your app can go to the background in many other ways - home button, selected notification, incoming phone call, etc.
You should check for the back button by overriding onKeyDown, not testing in onPause. onPause gets called whenever your activity is no longer in the background leaves the foreground; it is not necessarily finishing. (You can check isFinishing() for that.) See here for more info on handling the back key.
onPause is getting called, and your dialog is showing, just for a tiny split-second before Android finishes your app. Put log statements in there if you want to watch what is going on.
If you want to show a dialog when the back button is pressed then the easiest way (works on Android 2.1+) is to override the onBackPressed method in your activity
#Override
public void onBackPressed() {
if (gameRunning) {
// show dialog
} else {
// exit
super.onBackPressed();
}
}
Related
I want to know the default implementation of onBackPressed() in Activity. How to deal with the Activity recover in the default implementation of onBackPressed()?.
The following is the issues I suffer from. I have a test Activity code like this:
public class MainActivity extends Activity {
public static boolean test = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume() {
super.onResume();
Toast.makeText(this,"is "+test,Toast.LENGTH_LONG).show();
test = !test;
}
}
When I first enter the app, I get 'is false'. Then I click back button and get to the home screen. After that, when I enter the app, I get the Toast 'is true'. I think the onBackPressed() should kill my app when it gets back to the home screen, but It does not. This is my question.
If I override onBackPressed() like this
#Override
public void onBackPressed() {
// super.onBackPressed();
finish();
try {
android.os.Process.killProcess(android.os.Process.myPid());
} catch (Exception e) {
e.printStackTrace();
}
}
I always get the Toast 'is false' after I enter the app.
Can anyone explain this problem and tell me what the default implementation of onBackPressed()?
I'd like to know the flow process in onBackPressed() in detail. I have read some of the source code on onBackPressed(), but I couldn't understand it well.
Thanks in advance.
The default implementation of Activity's onBackPressed() probably won't tell you a lot about the actual Activity/application lifetime. You should dig much dipper to understand the internal Android (and Linux) "mechanics" on application/process killing.
What an application developer should know is that once an Activity is in background (Home button pressed, incoming call received etc., i.e. onPause() followed by onStop() have been invoked) its process may (similar to what you did with android.os.Process.killProcess(...)) or may NOT be killed. See Multitasking the Android Way by Dianne Hackborn for the reference.
As to finishing an Activity by pressing the back button, it does not mean its instance will be immediately killed and the memory garbage collected (see this answer). It just means a new instance of the Activity will be created next time you navigate back to it.
Regarding your code and the statement that
When I first enter the app, I get 'is false'. Then I click back button and get to the home screen. After that, when I enter the app, I get the Toast 'is true'. I think the onBackPressed() should kill my app when it gets back to the home screen, but It does not.
This is the case when the system didn't kill the process while the Activity were in background (again, it is not guaranteed). If it did, the Toast would have shown false.
In order to check that a new instance of MainActivity is created each time you press the back button and then navigate back to the app, I don't recommend to use a static variable, - it appears to be not that obvious (see, for instance, is it possible for Android VM to garbage collect static variables... or Are static fields open for garbage collection?).
Besides you're simply switching between true and false that might be confusing. Instead of using a static variable you might use a non-static one incrementing it, for example, or toast the hash code of the current Activity instance, like Toast.makeText(this,"is " + this.hashCode(), Toast.LENGTH_LONG).show(). By doing this the Activity lifecycle should act as per the documentation.
If I override onBackPressed() ... I always get the Toast 'is false' after I enter the app.
This is more or less similar to what if the system kills your app's process.
From the AOSP Activity class found here:
/**
* Called when the activity has detected the user's press of the back
* key. The default implementation simply finishes the current activity,
* but you can override this to do whatever you want.
*/
public void onBackPressed() {
if (mActionBar != null && mActionBar.collapseActionView()) {
return;
}
if (!mFragments.getFragmentManager().popBackStackImmediate()) {
finishAfterTransition();
}
}
So basically when you call finish, the process is not actually destroyed. You can read more about that here. This means that the memory in your app isn't destroyed, so when you restart your app, the boolean value from before is remembered.
In the case of your overridden implementation, you are explicitly destroying the process, which will clear memory of your activity state, so when you restart the app, the boolean initialization will occur again.
Is there any way to prevent executing code within onResume when returning to an application after the home button has been pressed?
What method is called when the home button is pressed? I could possibly flag something up when home button is pressed?
Thanks
After overriding above method, now you can easily listen HOME Key press in your activity using onKeyDown() method.
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_HOME)
{
//The Code Want to Perform.
}
});
Hope this will help
Thanks for the help everyone I managed to solve this by creating a boolean, executeOnResume, which I make false everytime onStop() is called and the app is closed. I then check the state of this boolean in onResume() when the app is opened again to choose whether some code should be executed or not.
onStop()
//-----application stopped
#Override
protected void onStop() {
super.onStop();
//do not execute onResume code when app opened again
executeOnResume = false;
}
onResume()
//-----application resumed
#Override
protected void onResume() {
super.onResume();
//if true
if (executeOnResume) {
//do something
}
else {
//execute onResume true code the next time onResume is called. For example, returning from another activity
}
}
tapping the Home button creates an intent to launch the Home screen and then starts that inten
Correct.
If this is the case, I'd expect the onCreate() method to be run whenever the Home screen is created
Not necessarily. If it is already running, it would be called with onNewIntent().
If someone could just offer some enlightenment into this matter, the basic question is whether onResume() or onCreate() gets called when I tap the Home button
Any time any activity returns to the foreground from a user input standpoint, onResume() is called. Home screens should be no different in this regard.
onCreate() is called when the activity is created. Existing activities are not created, but are merely brought back to the foreground. If what triggered the activity to return to the foreground was a startActivity() call, the activity will be called with onNewIntent() and onResume() (and usually onStart(), for that matter).
Reference : Which method is run when Home button pressed?
Users can leave your app in all kinds of different ways. Pressing HOME is only one of them. An incoming phone call will leave your app, pulling down the list of notifications and pressing one will leave your app, etc. In all of these cases, when the user returns to your app, onResume() will be called. This is standard Android behaviour and tells your app that it is now in the foreground and visible to the user.
Your architecture is flawed if you need to know how the user is returning to your app. You probably need to move some code that you have in onResume() back to onCreate() or onNewIntent().
I'm building an Android app specifically a log in page whereby I'd like the app to completely shut down the app if the user was to exit the log in page in any way i.e. using the SWITCH, HOME or BACK buttons.
The only time the app should not completely shut down should be when user successfully logs in i.e. when the custom created log in button or enter button is pressed.
I've been able to do successfully shut down the app but in shuts down even when the user successfully logs. It isn't meant to do this.
Below is my code for the complete shut down - I took over the onDestroy(), onBackPressed(), finish() and onStop() methods:
// Deal with back button
public void onBackPressed() {
System.runFinalizersOnExit(true);
System.exit(0);
}
// Deal with exiting of app
public void finish() {
System.runFinalizersOnExit(true);
System.exit(0);
}
// Deal with exiting of app
public void onDestroy() {
System.runFinalizersOnExit(true);
System.exit(0);
}
// Deal with exiting of app
public void onStop() {
System.runFinalizersOnExit(true);
System.exit(0);
}
DOES ANYONE HAVE ANY IDEAS REGARDING MY ISSUE
YOUR ASSISTANCE IS GREATLY APPRECIATED
Look here for an explanation of the onStop() method. I suppose you open another Activity when the user has successfully logged in, your Activity above becomes invisible and calls onStop() where you exit your app. So just don't override onStop().
The onStop() method is called each time your activity is made invisible: when your app goes to the background, when the screen is turned off, or when you switch to another activity.
Regardless, what you are trying to do is strongly discouraged.
See this forum thread (Dianne Hackborn being one of the lead developer of the Android Framework).
Force closing your app using System.exit(), Process.killProcess() and the likes has a strong risk of conflict with the Android application lifecycle, and can corrupt its saved state, leading to unexpected and unpleasant behaviors for your users.
A better way is to use the flags FLAG_ACTIVITY_SINGLE_TOP and FLAG_ACTIVITY_CLEAR_TOP when launching your login activity.
This should remove previous activities from application, which would be the same as starting a new application from a user point of view.
Just create a class member boolean mLoggedIn and set it to true when the custom created log in button or enter button is pressed.
Then
#Override
protected void onPause()
{
super.onPause();
if (!mLoggedIn)
{
finish();
}
}
My client wants their app to always show a "WARNING" screen when the application starts or when it awakens from sleep. I've tried creating an onResume() event in my master activity (which every other activity inherits from), but this causes an endless loop:
Activity is called, onResume() is fired
Warning screen fires, causing the calling activity to be paused
User clicks OK to accept the message, returning the user to the prior screen
Activity is woken up
Go to 1
Even if I could get around the endless loop, the Warning screen would fire whenever a new activity loads. This is what I like to call a Bad Thing.
Is there a way to mimic the onResume() event but at the application level rather than at the activity level, so that I can avoid these scenarios but still have the warning pop up on application wake?
Why not just use SharedPreferences.
http://android-er.blogspot.com/2011/01/example-of-using-sharedpreferencesedito.html
Store the time the popup is brought up, and if it was within 5 mins, or something, then don't pop it up.
This will break your loop and not completely annoy the user.
I would write a method to pop the warning and, in onPause, set a global flag. Check that global flag in the onResume, then reset it in your popup method. Simplified pseudo code...
class myApplication Extends Application{
boolean appIsPaused = false;
}
class myActivity Extends Activity{
#Override
protected void onPause(){
appIsPaused = true;
}
#Override
protected void onPause(){
if (appIsPaused){
showPopup();
}
}
public void showPopUp{
if (!appIsPaused){
return;
}
appIsPaused = false;
}
}
You could use an AlertDialog to show the warning message, it would solve your problem.
Else, try to start the warning screen from the onStart or onRestart of your application ?
Here's the android lifecycle if it can help : http://developer.android.com/reference/android/app/Activity.html
A snippet from the Android Activities document(scroll down to the "foreground lifetime" line) says :
An activity can frequently transition in and out of the foreground—for
example, onPause() is called when the device goes to sleep or when a
dialog appears.
I don't quite understand this. Under what circumstances should this happen? Is onPause() called only if the context of the dialog in question is different from the activity on top of which the dialog is to be displayed?
EDIT: Adding code sample to illustrate my doubt in detail
Going by the above-mentioned quote from document, should my activity's onPause() method get called when the AlertDialog (or just the Dialog) in the following code gets displayed? Should I see the "onPause called" log entry when the dialog is displayed?
But I don't see that happen. And it shouldn't either, if I have understood the Android life cycle correctly! So, what's the document pointing at then?
public class LifeCycleTestActivity extends Activity {
private static final String TAG = "LifeCycleTest";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn = (Button) findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "onClick");
AlertDialog dialog = new AlertDialog.Builder(LifeCycleTestActivity.this).create();
dialog.setMessage("You Clicked on the button");
dialog.setTitle("Dialog!");
dialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
dialog.setCancelable(true);
dialog.show();
/*
Dialog dialog = new Dialog(LifeCycleTestActivity.this);
dialog.setTitle("Dialog!");
dialog.setCancelable(true);
dialog.show();
*/
}
});
}
#Override
protected void onPause() {
Log.d(TAG, "onPause() called");
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume() called");
}
}
onPause() is called when your activity is no longer at the top of the activity stack. A Dialog by itself is not an Activity, so will not replace the current Activity at the top of the stack, so will not cause anything to pause.
A dialog (lower-case) does not need to be implemented by a Dialog class, however. For example, it is not uncommon to implement one with an Activity whose theme is set to that of a dialog. In this case, displaying the dialog-as-an-Activity will cause the new Activity to be on the top of the stack, pausing what previously was there.
I've been doing quite a lot of code with dialogs, including the AlertDialog that you mention, and I've also tried to check if onPause() is being called on the activity when the dialog pops up, but thus far my conclusion is that the activity simply keeps running and that onPause() is not called.
Not sure if it helps, but at least you now know that there are others who experience what you're experiencing :-)
Its wrong that activity remains no longer at top of activity stack in onPause phase.
Condition an activity to be onPause state -
Activity partially visible e.g. dialog on activity.
The Activity object is retained in memory, it maintains all state and member information, and remains attached to the window manager.
e.g Home button pressed causes activity to go in onPause(). Still at top of stack.
In fig 1. Activity3 will be destroyed and removed from top stack
In fig 2. Now Task A goes to background but Activty X still on top of stack . If you override onPause() method int this state
Figure 1. A representation of how each new activity in a task adds an item to the back stack. When the user presses the Back button, the current activity is destroyed and the previous activity resumes.
Figure 2. Two tasks: Task B receives user interaction in the foreground, while Task A is in the background, waiting to be resumed.
I think I remember reading in an earlier version of the Android Lifecycle that onPause was called when none of the activity is on display. i.e. if a bit of your activity is still visible under a popup, onPause will not be called.
Maybe some other experts can vouch for this behavior?
In my slightly weird experience onResume gets called with dialog.setCanceledOnTouchOutside(true); but onPause never gets called.
That being said, I think the documentation might focus on system dialogs (e.g. low on battery).
#hackbot
onPause() is called when your activity is no longer at the top of the activity >stack. A Dialog by itself is not an Activity, so will not replace the current >Activity at the top of the stack, so will not cause anything to pause.
everything depends on implementation...
what is a Dialog ? is a Window added to Display by WindowManager///
so the window when it shows is on top of everything .... (Z order)
what is activity... is "thing" that also creates its window....
when a dialog is shown or it's window comes visible on top of an existing activity, then it overrides partial the activity window so existing activity will move to partially invisible state and you will get call to onPause() from ActivityThread.
but to be sure we also need to consider here a one think...
the state of window if is a standalone window shown on top or it is a child window and a parent of it is a activity window....
so when we know
the Window.LayoutParams (FLAGS) we use to add
and what IBinder is used for the Window to show
we will khow how the activity will behave when windows are shown each over other .. as each winndow has a callbacks they are used by activity or dialog to manage their states...
involved components:
android.os.IBinder
android.view.Window
android.view.Window.Callback
android.view.WindowManager
android.view.WindowManager.LayoutParams
android.view.Display
btw:
if you want to know the windows on screen [ applicable only for the process you own - as window belongs to process and those are Sandboxed - each processs is a separate JVM strictly saying "ART" ] you can use a replection see :
android.view.WindowManagerImpl
android.view.WindowManagerGlobal
onPause() is called every Time when an Activity goes background and Dialog or other Activity comes foreGround. This is done to give first priority to something with which the user is interacting. e.g: assume you are in homescreen (which in turn is an activity) of an application, the homescreen is said to be in foreground. and when you go to next screen by pressing some button or a dialog appears the next screen/Activity/Dialog comes to foreGround and homecreen goes to backGround, which just means homeScreen's onPause() method got called.