it-roy-ru.com

Как показать диалоговое окно, чтобы подтвердить, что пользователь хочет выйти из Android Activity?

Я пытался показать "Вы хотите выйти?" тип диалога, когда пользователь пытается выйти из Activity. 

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

261
Peter A

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

}
380
jax
@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();
}
174
Chanakya Vadla

Изменили код @ 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();
    }

}
32
suraj jain

Я предпочел бы выйти с двойным нажатием на кнопку назад, чем с диалоговым окном выхода.

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

22
Toni Gamez

Если вы не уверены, что вызов «назад» выйдет из приложения или переместит пользователя на другое действие, вы можете свернуть вышеуказанные ответы в проверке 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();
}
20
GLee

в Китае большинство приложений подтвердит выход, нажав «дважды»: 

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
Siwei Shen 申思维

Сначала удалите 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();

}
5
Anjali-Systematix

Используя лямбду:

    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
vasiljevski
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();
                }
            }
        }
    }
2
Mohit Hooda

Мне нравится подход @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
marioosh

это отлично работает

@Override
public void onBackPressed() {
    if (mExitOnBackPress) finish();
    else {
        Toast.makeText(this, R.string.msg_confirm_exit, Toast.LENGTH_SHORT).show();
        mExitOnBackPress = true;
        new Android.os.Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mExitOnBackPress = false;
            }
        }, 2000);
    }
}
1
user3896501

Другой альтернативой может быть показать 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();
}
1
Kaushik NP

Если вы используете фрагмент вместо действия, включите этот код в основной вид деятельности. 

    private Toast toast;
    private long lastBackPressTime = 0;
    @SuppressLint("WrongConstant")
    @Override
    public void onBackPressed() {
        int fragments = getFragmentManager().getBackStackEntryCount();
        if (fragments == 0) {
            // make layout invisible since last fragment will be removed
            if (this.lastBackPressTime < System.currentTimeMillis() - 3000) {
                toast = Toast.makeText(this, "Press back again to close this app", 3000);
                toast.show();
                this.lastBackPressTime = System.currentTimeMillis();

            }else{
                if (toast != null) {
                    toast.cancel();
                }
                super.onBackPressed();
            }

        }else{
            if (toast != null) {
                toast.cancel();
            }
            super.onBackPressed();
        }
    }
0
Firefog