I have an app that has a few Spinners and a couple of Buttons that pop up Dialogs. Other Buttons start new Activities.
On startup, these all work fine. However, when a new Activity is started and then we return, all pop-up elements stop working properly - the screen dims, but no dialog appears. In this state:
if you tap where the dialog's buttons should be (such as an "OK" button), their callbacks are called and everything works fine
rotating the phone will cause a redraw and the dialog will be visible again
This seems to me to be an Android bug. There seem to be very few references to it anywhere, and I'm at a loss as to what triggers it, and how I can work around it. As requested by #ethan, code fragment for one possible path is below, but there's little to it; I don't need to return any results, and the problem is exhibited when the user simply presses the Back button (which just has the default binding).
private OnClickListener button_click = new OnClickListener()
{
public void onClick(View v) {
int lId = v.getId();
...
if ( lId == R.id.cancel_button ) {
finish();
}
...
}
}
This is probably not helpful - I'm hoping someone will recognize the symptom. In the meantime, I'm trying to work up a mock example that exhibits the problem.
It does not occur in 1.5 or 1.6, but does in 2.2.
Related
I'm doing a videogame. I wanted the application to have 3 screens. The presentation screen, the play screen, and the end screen.
I know that an activity can be started with an intent, but my problem is that in doing so, the last activity would be stacked, allowing the user to come back to the previous activity (or screen).
Is there a way to avoid this ?
use the finish() method inside the activity you want to close.
Although others have covered that you can simply call the finish() method to close down an activity if you do not want your user to be able to return to it, there is another issue I wish to cover quickly.
The Android Design Principles, or more specifically the Navigation Principles tell us that we should not be messing around with the default behaviour of the back button too much. A direct quote from the guide;
Consistent navigation is an essential component of the overall user
experience. Few things frustrate users more than basic navigation that
behaves in inconsistent and unexpected ways.
So, instead of preventing your users from being able to return to the entry screen, consider instead a prompt that notifies your user that they will be leaving the game. That way the back button continues to work as they would expect, and your users will not be suddenly dropped from gameplay. You can override the back button like so;
#Override
public void onBackPressed() {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("Leaving the Game");
alert.setMessage("Do you want to leave the game? You might lose your progress.");
alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
YourActivity.this.finish();
}
});
alert.setNegativeButton("Cancel", null );
alert.show();
}
Also, as a note, if you choose to simply close the previous Activity using finish(), the back button will then drop the user out of the app entirely because there is no Activity to go back to.
I am working on a game that takes a bit of time to reload its textures when the app loses focus. During this time, the app is unresponsive to the user.
I have setup a handler to tell the main Activity class when the textures are done loading so it can hide a ProgressDialog that I start when the user leaves the app as shown below:
#Override
public void onWindowFocusChanged(final boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (hasWindowFocus) {
if (this.windowLocked && this.gamePaused) {
this.gamePaused = false;
Cocos2dxHelper.onResume();
this.mGLSurfaceView.onResume();
}
this.windowLocked = false;
} else {
this.windowLocked = true;
}
}
#Override
protected void onResume() {
super.onResume();
if (!this.windowLocked && this.gamePaused) {
this.gamePaused = false;
Cocos2dxHelper.onResume();
this.mGLSurfaceView.onResume();
}
if (!this.dialogShowing && this.gamePaused) {
displayResumingDialog();
}
}
#Override
protected void onPause() {
super.onPause();
this.gamePaused = true;
Cocos2dxHelper.onPause();
this.mGLSurfaceView.onPause();
}
The functions to show and hide the dialog look like this:
static public void displayResumingDialog() {
dialogShowing = true;
resumingDialog = ProgressDialog.show(sContext, "Re-Initializing", "Please Wait...", true);
}
static public void hideResumingDialog() {
if (resumingDialog != null && resumingDialog.isShowing()) {
resumingDialog.dismiss();
dialogShowing = false;
}
}
This works absolutely fine if the user leaves the app via the home button and then comes back by opening the apps drawer and clicking the icon again. If they lock the screen and return, or hold down the home button and return from the list of running apps however, the dialog never gets hidden. In fact, everything except for the dialog stops running. If I setup the dialog to be dismissed when it is touched outside, and I dismiss it, the app is still hung until I press the Back button. Then after a few seconds the textures are reloaded and the game begins.
I've done a fair bit of logging trying to figure it out. All of the calls seem to be the same, except sometimes when the screen is locked, onResume gets called twice. I think my code accounts for that though. If I don't allow it to display when the screen is locked the code run through to the end with no problem. With the dialog up and the screen returns from being locked, the code stops once the dialog shows up so onSurfaceCreated never get called and the textures never have a chance to load. As I said, it doesn't resume until I dismiss the dialog and press the back button.
What would cause the ProgessDialog to completely take over like that? Perhaps more importantly, why does it do it when returning from a locked screen or running apps list but not when clicking on the app icon?
Well, I hate to answer my own question, but I figured out the problem and figured it might help someone else.
The dialog comes into focus when it is created, so the onWindowFocusChanged code never gets called, so the textures never get reloaded. I fixed it by making my dialog not focusable, like so:
resumingDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
Although the dialog locks up with the rest of the UI if the user returns from a locked screen at least it is there. I tried showing the dialog in an asynctask to get it to spin while the rest of the UI was locked up, but no such luck. If anyone can tell me how to get the dialog to spin I'd be glad to award the answer to that person. It spins if they come back to the app via the running apps list or the app's icon, just not from a locked screen.
I am developing a small app which shows passwords of the user through a Dialog screen.
When home button is pressed, I need to dim the screen (on the multi tasking window) so that any other person cannot see the password.
When user re-opens the app, it asks an application lock. But if the user leaves the password Dialog open and presses the home button, dialog and the password which user last looked at stays visible (on the multi tasking window) for a while (3-4 seconds!!) until a new dialog asks the lock.
So far I tried ever possible dialog.dissmiss() options. Dialog dismisses only when app is opened again (until a new lock dialog appears) even I put dismiss() in onPause, onStop etc.
Any idea appreciated.
I also tried,
android.os.Process.killProcess(android.os.Process.myPid());
this.finish();
System.exit(0);
none of them actually worked.
Suggestion 1: Double-check your implementation. Tying your dialog to the activity lifecycle seems like a good idea (especially to avoid leaked window errors as described here)
The following example works out well for me (with coachMark being derived from Dialog)
#Override
protected void onResume()
{
log.debug("onResume");
super.onResume();
// Show the coachMark depending on saved preference values
coachMark.mayBeShow();
}
#Override
protected void onPause()
{
log.debug("onPause");
// Hide the coachMark if it is showing to avoid leakedWindow errors
coachMark.maybeHide();
super.onPause();
}
onPause definately gets called when you press the home button, so if this approach does not work for you, try not recreating the dialog in the restarting part of the acitivty lifecycle (onRestart(), onStart() and onResume()) and see, if it gets dismissed correctly.
Suggestion 2: Should all of the above fail, you might consider overriding the home button as described here. I highly advise against it though, since this may cause the app to work in an way that the user does not expect it to.
I have a short question:
I'm new in the worl of android and I started now to programm a little app.
Now I have finished it and debugged it on my Samsung Galaxy S3. The application has 4 layouts. With a button you go to the next layout. So, I will, that if when I press the back softkey on my device, that it goes back to the last layout (like from layout 4 to layout 3).
When I tested it on my device, it always closes the app if I press the back softkey.
What can I do, that by pressing the app will change to the previous layout and closes if I press the back softkey if the main_actity is showed?
Thanks a lot for every answer.
With best regards
You can respond to the back press in the Activity's onBackPressed() callback. Please be careful that whatever you do makes sense from the user's perspective. Going back one "page" in your view hierarchy and closing the app after all that seems fine.
What you call a "new layout" should be a new activity/Fragment. Nothing else
Period
Do not try to change this behaviour.
Intent myIntent = new Intent(CurrentActivity.this, NextActivity.class);
CurrentActivity.this.startActivity(myIntent);
By your sayings, you want the back button to navigate between layouts. However the back button navigates through activities.
If you need the back button to do something else than navigating through activies, you have to include it in onBackPressed() method. For instance, if you want to move from layout2 to layout1 you an do this:
#Override
public void onBackPressed() {
//do something to hide layout2 and show layout1.
//You can use View.visibility or anything!
}
This is one of the plenty solutions.
You should enter these codes in current activity to goto wantedActivity when press back on your device :
onBackPressed()
{
startActivity(new(Intent(currentActivity.this , wantedActivity.class));
}
I've already discovered that you can't override the Home button on an Android phone. It exits the application, it ALWAYS exits the application, and it DOESN'T bother with any sort of namby-pamby confirmation. I suppose I understand Google's reasoning -- but I do think it's a bit short-sighted...
Anyway, (before I learned about the Home button), I set up my app so the user can exit the application through the Options Menu -- using onCreateOptionsMenu() and an XML file, I set up a simple pop-up menu that's displayed when the Menu button is pressed. One of its choices is Exit, and it works fine.
However, it occurred to me that it might be good practice to add a confirmation dialog to the exit process (even if it could also be considered superfluous). So, I created an AlertDialog with the title "Do you want to Exit?" and Yes and No buttons...
The click listeners for the buttons are simple and just set exitConfirm (a boolean) true or false. The code that handles the Exit menu choice then cleans up after my application and executes finish() or not depending on the state of exitConfirm...
Unfortunately, it completely doesn't work... All of the code in onOptionsItemSelected() for the exit case executes and THEN the Dialog is displayed!! I suppose I should've seen that coming. And I suppose if I keep pounding on it, I'll come up with a way accomplish this, but I thought I would ask the community for suggestions - so, does anybody have a suggestion for a way to smoothly exit an Android application in a manner that includes the step of getting confirmation from the user??
Thanks,
R.
First of all - this is a terrible practice. Asking for confirmation may be a nice option on a desktop application, but you're writing a mobile application. It's different. Actually, I need to write that in bold:
You are not writing a desktop application.
I recommend: No splash screen. No exit option. Definitely no exit confirmation. Here is an excellent question about it.
For your question: Use setPositiveButton and setNegativeButton to handle buttons.
Short answer:
You should read: When to Include an Exit Button in Android Apps.
Long answer:
You can try something like this:
protected Dialog onCreateDialog(int id) {
Dialog dialog = null;
switch (id) {
case MENU_QUIT:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(getString(R.string.main_screen_quit_text))
.setCancelable(false)
.setPositiveButton(
getString(R.string.main_screen_quit_yes),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int id) {
moveTaskToBack(true);
}
})
.setNegativeButton(getString(R.string.main_screen_quit_no),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
return alert;
default:
dialog = null;
}
return dialog;
}
Apparently, it's generally considered not to be cool to have an exit button (or menu item, or whatever) in your Android app. Apparently, this is because your application doesn't really exit. It's only minimized out of the way, and presumably, the OS will take care of it eventually.
However, if what you're doing requires some level of clean-up when you're done doing it, this is what I think I know about that:
Pay careful attention to the various Android "Life Cycle Methods", especially what kicks them off. Life cycle methods include onCreate(), onStart(), onResume(), onPause(), and onStop(). There's also onDestroy() -- the complement to onCreate() -- but I don't currently use it.
These methods are called in response to various events (like pressing the Home button), but what was important in my case was that minimizing the application calls onPause() and maximizing it calls onResume(). Hence, I needed to call my set up and tear down methods from those locations, and NOT, for instance, from onCreate() and onDestroy().
There is a function called finish() that I used to use all over my code. Now it's only in the method that's called to handle loss of communication with my external device. I believe the results of calling finish() are exactly the results of pressing the Home button -- so, it's just a way to "press" the Home button in software.
The long-winded conclusion to all this is the Home button absolutely WILL hide your application from the user's view. You cannot trap this key press -- no matter how badly you want to add some sort of, "Are you sure??" functionality. However, the app's been minimized, not closed, and this can either be good or bad. If you've written your start up and shut down code properly (and added it to the proper life cycle methods), you won't blow things up, and your user will be able to easily return to your app once they've learned to long press the Home button to see a list of minimized apps.
With any luck, I suppose, they'll blame their frustration on Google, and not on you...