Wie kann ein Dialogfeld angezeigt werden, um zu bestätigen, dass der Benutzer eine Android-Aktivität beenden möchte?


274

Ich habe versucht, ein "Willst du beenden?" Art des Dialogfelds, wenn der Benutzer versucht, eine Aktivität zu beenden.

Ich kann jedoch die entsprechenden API-Hooks nicht finden. Activity.onUserLeaveHint()Anfangs sah es vielversprechend aus, aber ich kann keinen Weg finden, die Aktivität am Ende zu hindern.


39
Ist es unbedingt erforderlich, dass Sie diese Eingabeaufforderung haben? Wenn ein Benutzer eine Aktivität beenden möchte, sollte er dies sofort tun können. Vielleicht möchten Sie Ihre Strategie überdenken.
Tom R

4
Das Anzeigen einer Exit-Bestätigungsoption ist für die Auflistung im Samsung App Store obligatorisch. Eine meiner Apps wurde abgelehnt, weil sie dies nicht hatte.
John Ashmore

6
Das ist widerlich, @Samsung.
Dokkaebi

3
Es hängt davon ab, was Sie beim Beenden tun möchten. Wenn der Status beibehalten wird und Sie einfach zurück navigieren können, ist das Anzeigen eines Dialogfelds möglicherweise nicht erforderlich. In einer meiner Anwendungen bereinige ich jedoch Cookies, Daten und enge Verbindungen endgültig mit einem endgültigen Festschreiben von Daten. Benutzer sollten auf die Endgültigkeit ihrer Wahl aufmerksam gemacht werden, zumal es heutzutage ungewöhnlich ist, dieses Gefühl der Endgültigkeit in einer mobilen Anwendung zu haben.
Eric

15
@ Tom R: Stimme überhaupt nicht zu. Es gibt Apps, die Sie nicht versehentlich beenden möchten. Sie arbeiten im Geschäftsumfeld und so weiter.
TomeeNS

Antworten:


390

In Android 2.0+ würde dies so aussehen:

@Override
public void onBackPressed() {
    new AlertDialog.Builder(this)
        .setIcon(android.R.drawable.ic_dialog_alert)
        .setTitle("Closing Activity")
        .setMessage("Are you sure you want to close this activity?")
        .setPositiveButton("Yes", new DialogInterface.OnClickListener()
    {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            finish();    
        }

    })
    .setNegativeButton("No", null)
    .show();
}

In früheren Versionen würde es so aussehen:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    //Handle the back button
    if(keyCode == KeyEvent.KEYCODE_BACK) {
        //Ask the user if they want to quit
        new AlertDialog.Builder(this)
        .setIcon(android.R.drawable.ic_dialog_alert)
        .setTitle(R.string.quit)
        .setMessage(R.string.really_quit)
        .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {

                //Stop the activity
                YourClass.this.finish();    
            }

        })
        .setNegativeButton(R.string.no, null)
        .show();

        return true;
    }
    else {
        return super.onKeyDown(keyCode, event);
    }

}

15
Ebenfalls in Version 2.0 und höher gibt es ein neues onBackPressed-Ereignis, das gegenüber onKeyDown developer.android.com/intl/zh-TW/reference/android/app/ empfohlen wird. Hier wird in einem Abschnitt über die Änderungen und den neuen empfohlenen Ansatz gesprochen. developer.android.com/intl/zh-TW/sdk/android-2.0.html
Patrick Kafka

3
Blog-Beitrag zum Abrufen der Zurück-Taste hier: android-developers.blogspot.com/2009/12/… Beachten Sie, dass Sie auf diese Weise keine anderen Möglichkeiten finden, wie der Benutzer Ihre App verlassen kann: Drücken der Startseite , Auswählen einer Benachrichtigung, Empfangen eines Telefons Anruf usw.
Hackbod

Dies funktioniert perfekt, aber wie erzwingen Sie, dass die Codeausführung angehalten wird, während sie dem Benutzer angezeigt wird?
anon58192932

fand es, dies ist eine großartige Lösung hier: stackoverflow.com/questions/4381296/…
anon58192932

1
Dies ist die Methode (), nach der ich suche, aber ich wusste nicht, wo ich diese Methode aufrufen soll ().
user2841300

186
@Override
public void onBackPressed() {
    new AlertDialog.Builder(this)
           .setMessage("Are you sure you want to exit?")
           .setCancelable(false)
           .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                   ExampleActivity.super.onBackPressed();
               }
           })
           .setNegativeButton("No", null)
           .show();
}

5
Ein Kommentar wurde von elBradford abgegeben: Das Aufrufen von super onBackPressed ist besser als die Annahme, dass onBackPressed nur finish () aufruft. Auch wenn das jetzt wahr ist, kann es in zukünftigen APIs nicht wahr seinCustomTabActivity.super.onBackPressed
mplungjan

@mplungjan Können Sie Ihren Kommentar klarstellen ... Wollen Sie damit sagen, dass es besser ist, den finish()Code durch zu ersetzen super.onBackPressed()?
Ban-Geoengineering

Kommentar ist 3 Jahre alt. Ich habe keine Ahnung, was gute Praxis im Jahr 2015 ist
mplungjan

@mplungjan Ihr Kommentar bezog sich auf zukünftige APIs, aber es wäre hilfreich, wenn Sie dies trotzdem klären könnten.
Ban-Geoengineering

Kein Problem. Nun, ich habe es gerade versucht MyActivity.super.onBackPressed();und es funktioniert gut für mich. Es erscheint auch am logischsten, die Methode aufzurufen, die Sie überschreiben, wenn Sie das Standardverhalten wünschen, wenn der Benutzer auf "Nein" tippt.
Ban-Geoengineering

33

Habe @ user919216 Code geändert .. und ihn mit WebView kompatibel gemacht

@Override
public void onBackPressed() {
    if (webview.canGoBack()) {
        webview.goBack();

    }
    else
    {
     AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Are you sure you want to exit?")
       .setCancelable(false)
       .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
                finish();
           }
       })
       .setNegativeButton("No", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
                dialog.cancel();
           }
       });
AlertDialog alert = builder.create();
alert.show();
    }

}

22

Ich würde es vorziehen, mit doppeltem Tippen auf die Zurück-Schaltfläche zu beenden, als mit einem Dialogfeld zum Beenden.

In dieser Lösung wird beim ersten Zurückgehen ein Toast angezeigt, der darauf hinweist, dass durch erneutes Drücken der App die App geschlossen wird. In diesem Beispiel weniger als 4 Sekunden.

private Toast toast;
private long lastBackPressTime = 0;

@Override
public void onBackPressed() {
  if (this.lastBackPressTime < System.currentTimeMillis() - 4000) {
    toast = Toast.makeText(this, "Press back again to close this app", 4000);
    toast.show();
    this.lastBackPressTime = System.currentTimeMillis();
  } else {
    if (toast != null) {
    toast.cancel();
  }
  super.onBackPressed();
 }
}

Token von: http://www.androiduipatterns.com/2011/03/back-button-behavior.html


Dieser ist definitiv mein Favorit, da das Dialogfeld umständlich sein kann. Ich habe es leicht geändert, um es auf 3 Sekunden zu bringen, und es scheint mit diesem Marker etwas natürlicher zu sein. Danke für den Beitrag.
PGMacDesign

Auf Double Back drücken Sie idealerweise die App, sollte ich beenden, aber in meinem Code ist eine Login-Aktivität geöffnet (bedeutet Back-Aktivität mit aktiviertem Spinner)
techDigi

21

Wenn Sie nicht sicher sind, ob der Aufruf von "Zurück" die App beendet oder den Benutzer zu einer anderen Aktivität führt, können Sie die obigen Antworten mit einem Häkchen versehen: isTaskRoot (). Dies kann passieren, wenn Ihre Hauptaktivität mehrmals zum Backstack hinzugefügt werden kann oder wenn Sie den Backstack-Verlauf bearbeiten.

if(isTaskRoot()) {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage("Are you sure you want to exit?")
       .setCancelable(false)
       .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
                YourActivity.super.onBackPressed;
           }
       })
       .setNegativeButton("No", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
                dialog.cancel();
           }
       });
    AlertDialog alert = builder.create();
    alert.show();

} else {
    super.onBackPressed();
}

5

Verwenden von Lambda:

    new AlertDialog.Builder(this).setMessage(getString(R.string.exit_msg))
        .setTitle(getString(R.string.info))
        .setPositiveButton(getString(R.string.yes), (arg0, arg1) -> {
            moveTaskToBack(true);
            finish();
        })
        .setNegativeButton(getString(R.string.no), (arg0, arg1) -> {
        })
        .show();

Sie müssen auch die Levelsprache festlegen, um Java 8 in Ihrem gradle.build zu unterstützen:

compileOptions {
       targetCompatibility 1.8
       sourceCompatibility 1.8
}

5

In China bestätigen die meisten Apps den Ausstieg durch "zweimal klicken":

boolean doubleBackToExitPressedOnce = false;

@Override
public void onBackPressed() {
    if (doubleBackToExitPressedOnce) {
        super.onBackPressed();
        return;
    }

    this.doubleBackToExitPressedOnce = true;
    Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();

    new Handler().postDelayed(new Runnable() {

        @Override
        public void run() {
            doubleBackToExitPressedOnce=false;                       
        }
    }, 2000);
} 

5

Entfernen Sie zuerst super.onBackPressed();von der onbackPressed()Methode als und unter dem Code:

@Override
public void onBackPressed() {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage("Are you sure you want to exit?")
           .setCancelable(false)
           .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                    MyActivity.this.finish();
               }
           })
           .setNegativeButton("No", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
               }
           });
    AlertDialog alert = builder.create();
    alert.show();

}

2

Ich mag einen @ GLee-Ansatz und verwende ihn mit Fragmenten wie unten.

@Override
public void onBackPressed() {
    if(isTaskRoot()) {
        new ExitDialogFragment().show(getSupportFragmentManager(), null);
    } else {
        super.onBackPressed();
    }
}

Dialog mit Fragment:

public class ExitDialogFragment extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return new AlertDialog.Builder(getActivity())
            .setTitle(R.string.exit_question)
            .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    getActivity().finish();
                }
            })
            .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    getDialog().cancel();
                }
            })
            .create();
    }
}

2
Just put this code in your first activity 

@Override
    public void onBackPressed() {
        if (drawerLayout.isDrawerOpen(GravityCompat.END)) {
            drawerLayout.closeDrawer(GravityCompat.END);
        }
        else {
// if your using fragment then you can do this way
            int fragments = getSupportFragmentManager().getBackStackEntryCount();
            if (fragments == 1) {
new AlertDialog.Builder(this)
           .setMessage("Are you sure you want to exit?")
           .setCancelable(false)
           .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                    finish();
               }
           })
           .setNegativeButton("No", null)
           .show();


            } else {
                if (getFragmentManager().getBackStackEntryCount() > 1) {
                    getFragmentManager().popBackStack();
                } else {

           super.onBackPressed();
                }
            }
        }
    }

y erste Aktivität, kann ich es nicht in Aktivität in der Mitte setzen. denn jetzt schließt es jsut die aktuelle Aktivität und es zeigt die vorherige
shareef

1

Eine andere Alternative wäre, ein Toast/ Snackbarbeim ersten Zurückdrücken anzuzeigen und zu bitten, erneut auf Beenden zu drücken , was viel weniger aufdringlich ist als das Anzeigen eines AlertDialog, um zu bestätigen, ob der Benutzer die App beenden möchte.

Sie können das verwenden DoubleBackPress Android Library, um dies mit ein paar Codezeilen zu erreichen. Beispiel GIF mit ähnlichem Verhalten.

Fügen Sie Ihrer Anwendung zunächst die Abhängigkeit hinzu:

dependencies {
    implementation 'com.github.kaushikthedeveloper:double-back-press:0.0.1'
}

Implementieren Sie als Nächstes in Ihrer Aktivität das erforderliche Verhalten.

// set the Toast to be shown on FirstBackPress (ToastDisplay - builtin template)
// can be replaced by custom action (new FirstBackPressAction{...})
FirstBackPressAction firstBackPressAction = new ToastDisplay().standard(this);

// set the Action on DoubleBackPress
DoubleBackPressAction doubleBackPressAction = new DoubleBackPressAction() {
    @Override
    public void actionCall() {
        // TODO : Exit the application
        finish();
        System.exit(0);
    }
};

// setup DoubleBackPress behaviour : close the current Activity
DoubleBackPress doubleBackPress = new DoubleBackPress()
        .withDoublePressDuration(3000)     // msec - wait for second back press
        .withFirstBackPressAction(firstBackPressAction)
        .withDoubleBackPressAction(doubleBackPressAction);

Stellen Sie dies schließlich als Verhalten beim Zurückdrücken ein.

@Override
public void onBackPressed() {
    doubleBackPress.onBackPressed();
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.