本文翻译自:Clicking the back button twice to exit an activity
I've noticed this pattern in a lot of Android apps and games recently: when clicking the back button to "exit" the application, a Toast
comes up with a message similar to "Please click BACK again to exit". 我最近在很多Android应用和游戏中都注意到了这种模式:当点击后退按钮“退出”应用程序时, Toast
会出现类似于“请再次单击BACK退出”的消息。
I was wondering, as I'm seeing it more and more often, is that a built-in feature that you can somehow access in an activity? 我想知道,因为我越来越频繁地看到它是一个内置的功能,你可以以某种方式访问活动? I've looked at the source code of many classes but I can't seem to find anything about that. 我查看了许多类的源代码,但我似乎无法找到任何相关内容。
Of course, I can think about a few ways to achieve the same functionality quite easily (the easiest is probably to keep a boolean in the activity that indicates whether the user already clicked once...) but I was wondering if there's something already here. 当然,我可以考虑几种方法来轻松实现相同的功能(最容易的是在活动中保留一个布尔值,表明用户是否已经点击过一次......)但是我想知道这里是否有东西。
EDIT : As @LAS_VEGAS mentioned, I didn't really mean "exit" in the traditional meaning. 编辑 :正如@LAS_VEGAS所说,我并不是指传统意义上的“退出”。 (ie terminated) I meant "going back to whatever was open before the application start activity was launched", if that makes sense :) (即已终止)我的意思是“回到应用程序启动活动启动之前打开的任何内容”,如果这有意义:)
#1楼
参考:https://stackoom.com/question/ZNEj/单击后退按钮两次以退出活动
#2楼
In Java Activity: 在Java活动中:
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);
}
In Kotlin Activity: 在Kotlin活动中:
private var doubleBackToExitPressedOnce = false
override fun onBackPressed() {
if (doubleBackToExitPressedOnce) {
super.onBackPressed()
return
}
this.doubleBackToExitPressedOnce = true
Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show()
Handler().postDelayed(Runnable { doubleBackToExitPressedOnce = false }, 2000)
}
I Think this handler helps to reset the variable after 2 second. 我认为这个处理程序有助于在2秒后重置变量。
#3楼
Process Flow Diagram: 流程图:
Java Code: Java代码:
private long lastPressedTime;
private static final int PERIOD = 2000;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
switch (event.getAction()) {
case KeyEvent.ACTION_DOWN:
if (event.getDownTime() - lastPressedTime < PERIOD) {
finish();
} else {
Toast.makeText(getApplicationContext(), "Press again to exit.",
Toast.LENGTH_SHORT).show();
lastPressedTime = event.getEventTime();
}
return true;
}
}
return false;
}
#4楼
I know this is a very old question, but this is the easiest way to do what you want. 我知道这是一个非常古老的问题,但这是做你想做的最简单的方法。
@Override
public void onBackPressed() {
++k; //initialise k when you first start your activity.
if(k==1){
//do whatever you want to do on first click for example:
Toast.makeText(this, "Press back one more time to exit", Toast.LENGTH_LONG).show();
}else{
//do whatever you want to do on the click after the first for example:
finish();
}
}
I know this isn't the best method, but it works fine! 我知道这不是最好的方法,但它工作正常!
#5楼
Based upon the correct answer and suggestions in comments, I have created a demo which works absolutely fine and removes the handler callbacks after being used. 根据正确的答案和评论中的建议,我创建了一个完全正常的演示,并在使用后删除处理程序回调。
MainActivity.java MainActivity.java
package com.mehuljoisar.d_pressbacktwicetoexit;
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.widget.Toast;
public class MainActivity extends Activity {
private static final long delay = 2000L;
private boolean mRecentlyBackPressed = false;
private Handler mExitHandler = new Handler();
private Runnable mExitRunnable = new Runnable() {
@Override
public void run() {
mRecentlyBackPressed=false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void onBackPressed() {
//You may also add condition if (doubleBackToExitPressedOnce || fragmentManager.getBackStackEntryCount() != 0) // in case of Fragment-based add
if (mRecentlyBackPressed) {
mExitHandler.removeCallbacks(mExitRunnable);
mExitHandler = null;
super.onBackPressed();
}
else
{
mRecentlyBackPressed = true;
Toast.makeText(this, "press again to exit", Toast.LENGTH_SHORT).show();
mExitHandler.postDelayed(mExitRunnable, delay);
}
}
}
I hope it will be helpful !! 我希望它会有所帮助!!
#6楼
Sudheesh B Nair 's has a nice (and accepted) answer on the question, which i think should have a better alternative such as; Sudheesh B Nair在这个问题上有一个很好的(并且被接受的)答案,我认为应该有更好的选择,例如;
What's wrong with measuring time passed and checking if TIME_INTERVAL
miliseconds (say 2000) passed since the last back press. 测量时间过去并检查自上次反压后是否已经过了TIME_INTERVAL
毫秒(比如2000),这有什么问题。 The following sample code uses System.currentTimeMillis();
以下示例代码使用System.currentTimeMillis();
to store the time onBackPressed()
is called; 存储时间onBackPressed()
被调用;
private static final int TIME_INTERVAL = 2000; // # milliseconds, desired time passed between two back presses.
private long mBackPressed;
@Override
public void onBackPressed()
{
if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis())
{
super.onBackPressed();
return;
}
else { Toast.makeText(getBaseContext(), "Tap back button in order to exit", Toast.LENGTH_SHORT).show(); }
mBackPressed = System.currentTimeMillis();
}
Back on accepted answer critique ; 回到接受的答案批评 ; Using a flag
to indicate if it was pressed in last TIME_INTERVAL
(say 2000) milliseconds and set - reset is via Handler
's postDelayed()
method was the first thing to come in my mind. 使用一个flag
来指示它是否在最后的TIME_INTERVAL
(比如2000)毫秒内被按下并设置 - 重置是通过Handler
的postDelayed()
方法是我想到的第一件事。 But the postDelayed()
action should be cancelled when activity is closing, removing the Runnable
. 但是当活动结束时,应该取消postDelayed()
动作,删除Runnable
。
In order to remove the Runnable
, it must not be declared anonymous , and be declared as member along with the Handler
aswell. 为了删除Runnable
,它不能声明为匿名 ,并且与Handler
一起声明为成员。 Then removeCallbacks()
method of Handler
can be called appropriately. 然后可以适当地调用Handler
removeCallbacks()
方法。
The following sample is the demonstration; 以下示例是演示;
private boolean doubleBackToExitPressedOnce;
private Handler mHandler = new Handler();
private final Runnable mRunnable = new Runnable() {
@Override
public void run() {
doubleBackToExitPressedOnce = false;
}
};
@Override
protected void onDestroy()
{
super.onDestroy();
if (mHandler != null) { mHandler.removeCallbacks(mRunnable); }
}
@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();
mHandler.postDelayed(mRunnable, 2000);
}
Thanks to @NSouth for contributing; 感谢@NSouth的贡献; In order to prevent toast message appearing even after the application is closed, Toast
can be declared as a member - say mExitToast
- and can be cancelled via mExitToast.cancel();
为了防止在应用程序关闭后出现toast消息 ,可以将Toast
声明为成员 - 例如mExitToast
- 并可以通过mExitToast.cancel();
取消mExitToast.cancel();
just before super.onBackPressed();
就在super.onBackPressed();
之前super.onBackPressed();
call. 呼叫。