如何显示对话框以确认用户希望退出Android活动?


274

我一直在尝试显示“您要退出吗?” 用户尝试退出活动时的对话框类型。

但是我找不到合适的API挂钩。 Activity.onUserLeaveHint()最初看起来很有希望,但我找不到阻止活动结束的方法。


39
提示是否绝对必要?当用户想要完成一个活动时,他们应该能够立即完成。您可能需要重新考虑您的策略。
汤姆R 2010年

4
必须显示退出确认选项才能在Samsung App Store上列出。我的一个应用因为没有此功能而被拒绝。
John Ashmore

6
真讨厌,@三星。
dokkaebi

3
这取决于您退出时要执行的操作。如果状态被保留并且您可以向后浏览,则可能无需显示对话框。但是,在我的一个应用程序中,我最终清理了cookie,数据并关闭了连接并最终提交了数据。应该使用户知道他们选择的确定性,尤其是因为在移动应用程序中具有最终确定性的今天并不常见。
埃里克

15
// @汤姆R:完全不同意。有些应用程序是您不希望意外完成的。他们在商业环境中工作等等。
TomeeNS

Answers:


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及更高版本中,建议在onKeyDown developer.android.com/intl/zh-TW/reference/android/app/上推荐一个新的onBackPressed事件。 这里有一节讨论更改和推荐的新方法。 developer.android.com/intl/zh-TW/sdk/android-2.0.html
Patrick Kafka,2010年

3
有关在此处获取后退键的博客文章: android-developers.blogspot.com/2009/12/… 请注意,这不允许您捕获用户离开应用程序的其他方式:按下主页,选择通知,接听电话电话等
hackbod 2010年

这完美地工作了,但是当代码显示给用户时,如何强制代码执行停止?
anon58192932 2013年

发现它,这是一个很好的解决方案在这里:stackoverflow.com/questions/4381296/...
anon58192932

1
这是我正在寻找的method(),但是我不知道在哪里调用此method()。
user2841300 2013年

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发表评论:调用super onBackPressed比假设onBackPressed仅调用finish()更好。即使现在是对的,在将来的API中也可能不对CustomTabActivity.super.onBackPressed
mplungjan

@mplungjan您可以澄清您的评论吗?您是说最好用替换finish()代码super.onBackPressed()吗?
ban-geoengineering

评论已有3年历史了。我不知道2015
-mplungjan

@mplungjan您的评论涉及未来的API,但是如果您仍然可以进行澄清,将对您有所帮助。
ban-geoengineering

没有问题。好吧,我刚刚尝试过MyActivity.super.onBackPressed();,对我来说效果很好。这似乎也是最合乎逻辑的方法-如果希望用户点击“否”时的标准行为,则调用您要覆盖的方法。
ban-geoengineering

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

在双后按上,理想情况下,应用程序应该退出,但在我的代码中它打开了一个登录活动(表示启用了旋转器的活动)
techDigi 16-10-10

21

如果不确定对“ back”的调用是退出应用程序还是将用户带到其他活动,则可以将上述答案包装在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

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

您还需要在gradle.build中设置级别语言以支持Java 8:

compileOptions {
       targetCompatibility 1.8
       sourceCompatibility 1.8
}

5

在中国,大多数App都会通过“单击两次”来确认退出:

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()than和以下代码中删除方法:

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

您的第一次活动是,我不能将其放在中间的活动中。因为现在jsut关闭了当前活动,并且显示了上一个活动
shareef

1

另一种选择是在第一次按下时显示Toast/ Snackbar,要求再次按下返回Exit,这比显示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();
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.