Як показати діалогове вікно, щоб підтвердити, що користувач бажає вийти з активності Android?


274

Я намагався показати "Ви хочете вийти?" тип діалогового вікна, коли користувач намагається вийти з дії.

Однак я не можу знайти відповідні гачки API. Activity.onUserLeaveHint()спочатку виглядало багатообіцяюче, але я не можу знайти спосіб зупинити діяльність на завершенні.


39
Чи абсолютно важливо, що у вас є цей підказки? Коли користувач хоче закінчити діяльність, він повинен мати можливість це зробити негайно. Ви можете переосмислити свою стратегію.
Том R

4
Відображення параметра підтвердження виходу є обов’язковим для перегляду в магазині додатків Samsung. Одне з моїх додатків було відхилено через відсутність цього.
Джон Ешмор

6
Це неприємно, @Samsung.
dokkaebi

3
Це залежить від того, що ви хочете зробити при виході. Якщо стан збережено, і ви можете просто перейти назад, показ діалогового вікна може бути не потрібним. Однак в одному з моїх додатків я очищаю файли cookie, дані та добре закриваю зв’язки назавжди з остаточним фіксуванням даних. Користувачам слід ознайомитись з остаточністю свого вибору, тим більше, що сьогодні рідко виникає відчуття остаточності в мобільному додатку.
Ерік

15
@ Tom R: Повністю не згоден. Є програми, які ви не хочете закінчити випадково. Вони працюють у бізнес-середовищі тощо.
TomeeNS

Відповіді:


390

В Android 2.0+ це виглядатиме так:

@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();
}

У попередніх версіях це виглядатиме так:

@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
Також в версії 2.0 і вище є нова подія onBackPress, яку рекомендується використовувати на сайтіKeyDown developer.android.com/intl/zh-TW/reference/android/app/… Тут є розділ, який розповідає про зміни та новий рекомендований підхід. developer.android.com/intl/zh-TW/sdk/android-2.0.html
Патрік Кафка

3
Повідомлення в блозі про введення ключа назад тут: android-developers.blogspot.com/2009/12/… Зауважте, що це не дозволяє вам знайти інші способи, як користувач може залишити ваш додаток: натискання додому, вибір повідомлення, отримання телефону дзвінок тощо
hackbod

Це чудово працює, але як змусити зупинити виконання коду, поки його показують користувачеві?
anon58192932

знайшов, що це відмінне рішення тут: stackoverflow.com/questions/4381296 / ...
anon58192932

1
Це метод (), який я шукаю, але я не знав, куди закликати цей метод ().
користувач2841300

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
Коментар зробив elBradford: Виклик супер onBackPress краще, ніж припускати, що onBackPress буде лише завершення виклику (). Навіть якщо це правда зараз, це може бути неправдою в майбутніх APICustomTabActivity.super.onBackPressed
mplungjan

@mplungjan Чи можете ви пояснити свій коментар ... Ви хочете сказати, що краще замінити finish()код на super.onBackPressed()?
заборона-геоінженерія

Коментар 3 роки. Я поняття не маю, яка хороша практика у 2015 році
mplungjan

@mplungjan Ваш коментар стосувався майбутніх API, але було б корисно, якщо ви все-таки зможете уточнити.
заборона-геоінженерія

Жодних проблем. Ну, я щойно спробував, MyActivity.super.onBackPressed();і це прекрасно працює для мене. Це також видається найбільш логічним підходом - викликати метод, який ви переосмислюєте, якщо ви хочете стандартної поведінки, коли користувач натискає "Ні".
заборона-геоінженерія

33

Змінили код @ user919216 .. та зробили його сумісним із WebView

@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

Я вважаю за краще вийти з подвійним натисканням на кнопку "назад", ніж за допомогою діалогового вікна виходу.

У цьому рішенні він показує тост при першому поверненні назад, попереджаючи, що додаткове натискання назад закриє додаток. У цьому прикладі менше 4 секунд.

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();
 }
}

Маркер від: http://www.androiduipatterns.com/2011/03/back-button-behavior.html


Цей, безумовно, мій улюблений, оскільки діалогове вікно може бути громіздким. Я трохи змінив його, щоб зробити це 3 секунди, і це здається трохи більш природним із цим маркером. Дякую за пост.
PGMacDesign

при подвійному зворотному натисканні в ідеалі додаток, якщо мені потрібно вийти, але в моєму коді це відкрита вхід Активність (означає активність зворотного зв’язку з включеним
спінером

21

Якщо ви не впевнені, що виклик «назад» закриє додаток, або переведе користувача на іншу діяльність, ви можете перегорнути вищезазначені відповіді в чек, isTaskRoot (). Це може статися, якщо ваша основна діяльність може бути додана до заднього стека кілька разів, або якщо ви маніпулюєте історією заднього стека.

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

Використання лямбда:

    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();

Вам також потрібно встановити мову рівня для підтримки Java 8 у вашому gradle.build:

compileOptions {
       targetCompatibility 1.8
       sourceCompatibility 1.8
}

5

у Китаї більшість додатків підтвердить вихід "натисніть двічі":

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

Спочатку видаліть super.onBackPressed();із onbackPressed()методу, ніж і нижче код:

@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

Мені подобається підхід @GLee і використовую його з фрагментом, як показано нижче.

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

Діалогове вікно за допомогою фрагмента:

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 перша діяльність, не можу я поставити його в активності в середині. тому що тепер jsut закриває поточну активність, і вона показує попередню
shareef

1

Інша альтернатива була б показати Toast/ Snackbarна першу задню пресу з проханням преси знову на вихід , який є набагато менш нав'язливим , ніж , що показує , AlertDialogщоб підтвердити , якщо користувач хоче , щоб вийти з програми.

Для цього можна скористатися DoubleBackPress Android Libraryкількома рядками коду. Приклад GIF, що показує подібну поведінку.

Для початку додайте залежність до своєї програми:

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

Далі, у своїй діяльності, реалізуйте необхідну поведінку.

// 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);

Нарешті, встановіть це як поведінку на зворотному пресі.

@Override
public void onBackPressed() {
    doubleBackPress.onBackPressed();
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.