单击back按钮两次以退出活动

我最近在许多Android应用和游戏中注意到这种模式:当单击后退按钮以“退出”应用程序时,Toast会出现类似“请再次单击后退以退出”的消息。

我在想,当我越来越频繁地看到它时,这是一个内置的功能,你可以在某个活动中访问它吗?我已经看了很多类的源代码,但我似乎找不到任何关于这一点。

当然,我可以想到一些很容易实现相同功能的方法(最简单的可能是在活动中保留一个布尔值,指示用户是否已经单击过一次…),但我想知道这里是否已经有一些东西。

编辑:正如@LAS_VEGAS提到的,我并不是指传统意义上的“退出”。(即终止)我的意思是“回到应用程序启动活动启动之前打开的任何东西”,如果这有意义的话:)

291100 次浏览

它不是内置的功能。我认为这甚至不是被推荐的行为。Android应用程序并不意味着退出:

为什么Android应用程序不提供&;退出&;选择吗?< / >

我只是想分享一下我是如何做到的,我只是在我的活动中添加了:

private boolean doubleBackToExitPressedOnce = false;


@Override
protected void onResume() {
super.onResume();
// .... other stuff in my onResume ....
this.doubleBackToExitPressedOnce = false;
}


@Override
public void onBackPressed() {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, R.string.exit_press_back_twice_message, Toast.LENGTH_SHORT).show();
}

它就像我想要的那样工作。包括每当活动恢复时对状态的重置。

在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(Looper.getMainLooper()).postDelayed(new Runnable() {
        

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

在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(Looper.getMainLooper()).postDelayed(Runnable { doubleBackToExitPressedOnce = false }, 2000)
}

我认为这个处理程序有助于在2秒后重置变量。

工艺流程图: 再次按下退出。 < / p >

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

我知道这是一个很老的问题,但这是你想做的最简单的方法。

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

我知道这不是最好的方法,但它很有效!

根据正确的答案和评论中的建议,我创建了一个演示,工作绝对很好,并在使用后删除处理程序回调。

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


}

希望对大家有所帮助!!

Sudheesh B Nair's对这个问题有一个很好的(和公认的)答案,我认为应该有一个更好的选择,如;

测量过去的时间并检查自上次背按以来是否经过了TIME_INTERVAL毫秒(比如2000)有什么问题。下面的示例代码使用System.currentTimeMillis();存储调用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();
}

回到已接受的答案批判;我首先想到的是使用flag来指示它是否在最近的TIME_INTERVAL(比如2000)毫秒内被按下,而设置-重置是通过HandlerpostDelayed()方法按下的。但是当活动关闭时,postDelayed()操作应该被取消,从而删除Runnable

为了移除Runnable,它不能被声明为匿名,必须和Handler一起声明为成员。然后可以适当地调用HandlerremoveCallbacks()方法。

下面的示例是演示;

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

感谢@NSouth的贡献;为了防止在应用程序关闭后仍然出现烤面包的消息Toast可以被声明为一个成员——比如mExitToast——并且可以在调用super.onBackPressed();之前通过mExitToast.cancel();取消。

@Override public void onBackPressed() {
Log.d("CDA", "onBackPressed Called");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);


startActivity(intent);
}

Zefnus的答案使用System.currentTimeMillis()是最好的答案(+1)。我这样做的方式是比那更好,但仍然张贴它,以补充以上的想法。

如果返回按钮按下时toast不可见,则显示toast,反之,如果它可见(在最近的Toast.LENGTH_SHORT时间内,back已经按过一次),则退出。

exitToast = Toast.makeText(this, "Press again to exit", Toast.LENGTH_SHORT);
.
.
@Override
public void onBackPressed() {
if (exitToast.getView().getWindowToken() == null) //if toast is currently not visible
exitToast.show();  //then show toast saying 'press againt to exit'
else {                                            //if toast is visible then
finish();                                      //or super.onBackPressed();
exitToast.cancel();
}
}

在所有这些答案中,有一个非常简单的方法。

只需在onBackPressed()方法中编写以下代码。

long back_pressed;


@Override
public void onBackPressed() {
if (back_pressed + 1000 > System.currentTimeMillis()){
super.onBackPressed();
}
else{
Toast.makeText(getBaseContext(),
"Press once again to exit!", Toast.LENGTH_SHORT)
.show();
}
back_pressed = System.currentTimeMillis();
}

你需要在activity中将back_pressed对象定义为long

最近,我需要在我的一个应用程序中实现这个后退按钮功能。对最初问题的回答是有用的,但我必须考虑到另外两点:

  1. 在某些时间点,返回按钮被禁用
  2. 主要的活动是将片段与反向堆栈结合使用

根据回答和评论,我创建了以下代码:

private static final long BACK_PRESS_DELAY = 1000;


private boolean mBackPressCancelled = false;
private long mBackPressTimestamp;
private Toast mBackPressToast;


@Override
public void onBackPressed() {
// Do nothing if the back button is disabled.
if (!mBackPressCancelled) {
// Pop fragment if the back stack is not empty.
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
super.onBackPressed();
} else {
if (mBackPressToast != null) {
mBackPressToast.cancel();
}


long currentTimestamp = System.currentTimeMillis();


if (currentTimestamp < mBackPressTimestamp + BACK_PRESS_DELAY) {
super.onBackPressed();
} else {
mBackPressTimestamp = currentTimestamp;


mBackPressToast = Toast.makeText(this, getString(R.string.warning_exit), Toast.LENGTH_SHORT);
mBackPressToast.show();
}
}
}
}

上面的代码假设使用了支持库。如果你使用片段而不是支持库,你想用getFragmentManager()替换getSupportFragmentManager()

如果后退按钮从未取消,则删除第一个if。如果不使用片段或片段回栈,则删除第二个if

此外,重要的是要意识到方法onBackPressed自Android 2.0开始支持。检查这个页面以获得详细的描述。为了使背按功能也适用于旧版本,将以下方法添加到您的活动中:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event)  {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ECLAIR
&& keyCode == KeyEvent.KEYCODE_BACK
&& event.getRepeatCount() == 0) {
// Take care of calling this method on earlier versions of
// the platform where it doesn't exist.
onBackPressed();
}


return super.onKeyDown(keyCode, event);
}

退出应用程序时使用Runnable并不是一个好主意,我最近想出了一个更简单的方法来记录和比较两次后退按钮点击之间的时间。示例代码如下:

private static long back_pressed_time;
private static long PERIOD = 2000;


@Override
public void onBackPressed()
{
if (back_pressed_time + PERIOD > System.currentTimeMillis()) super.onBackPressed();
else Toast.makeText(getBaseContext(), "Press once again to exit!", Toast.LENGTH_SHORT).show();
back_pressed_time = System.currentTimeMillis();
}

这将在特定的延迟时间内(样本为2000毫秒)单击两次BACK按钮来退出应用程序。

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

声明变量private boolean doubleBackToExitPressedOnce = false;

将此粘贴到您的主活动,这将解决您的问题

接受的答案是最好的,但如果你正在使用Android Design Support Library,那么你可以使用SnackBar来获得更好的视图。

   boolean doubleBackToExitPressedOnce = false;


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


this.doubleBackToExitPressedOnce = true;


Snackbar.make(findViewById(R.id.photo_album_parent_view), "Please click BACK again to exit", Snackbar.LENGTH_SHORT).show();


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


@Override
public void run() {
doubleBackToExitPressedOnce=false;
}
}, 2000);
}
  1. 为MainActivity类声明一个全局Toast变量。示例:Toast exitToast;
  2. 在onCreate视图方法中初始化它。例子: exitToast = Toast.makeText(getApplicationContext(), "Press back again to exit", Toast.LENGTH_SHORT); . exitToast = Toast.makeText(getApplicationContext(), "Press back to exit", Toast.LENGTH_SHORT)
  3. 最后创建一个onBackPressedMethod,如下所示:

    @Override
    public void onBackPressed() {
    
    
    if (exitToast.getView().isShown()) {
    exitToast.cancel();
    finish();
    } else {
    exitToast.show();
    }
    }
    

This works correctly, i have tested. and I think this is much simpler.

boolean doubleBackToExitPressedOnce = false;


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


this.doubleBackToExitPressedOnce = true;


Snackbar.make(findViewById(R.id.photo_album_parent_view), "Please click BACK again to exit", Snackbar.LENGTH_SHORT).show();


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


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

为此,我实现了以下函数:

private long onRecentBackPressedTime;
@Override
public void onBackPressed() {
if (System.currentTimeMillis() - onRecentBackPressedTime > 2000) {
onRecentBackPressedTime = System.currentTimeMillis();
Toast.makeText(this, "Please press BACK again to exit", Toast.LENGTH_SHORT).show();
return;
}
super.onBackPressed();
}

在Sudheesh B Nair的回答中有一些改进,我注意到它会等待处理程序,即使在立即按回两次,所以取消处理程序如下所示。我已经取消吐司也防止它显示后应用程序退出。

 boolean doubleBackToExitPressedOnce = false;
Handler myHandler;
Runnable myRunnable;
Toast myToast;


@Override
public void onBackPressed() {
if (doubleBackToExitPressedOnce) {
myHandler.removeCallbacks(myRunnable);
myToast.cancel();
super.onBackPressed();
return;
}


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


myHandler = new Handler();


myRunnable = new Runnable() {


@Override
public void run() {
doubleBackToExitPressedOnce = false;
}
};
myHandler.postDelayed(myRunnable, 2000);
}

我认为这是一个比Zefnus更好的方法。只调用一次System.currentTimeMillis(),并省略return;:

long previousTime;


@Override
public void onBackPressed()
{
if (2000 + previousTime > (previousTime = System.currentTimeMillis()))
{
super.onBackPressed();
} else {
Toast.makeText(getBaseContext(), "Tap back button in order to exit", Toast.LENGTH_SHORT).show();
}
}

当你将之前的堆栈活动存储在堆栈中时,这也会有所帮助。

我修改了Sudheesh的答案

boolean doubleBackToExitPressedOnce = false;


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


Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);//***Change Here***
startActivity(intent);
finish();
System.exit(0);
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);
}

你可以使用小吃店而不是吐司,所以你可以依靠它们的可见性来决定是否关闭应用程序。举个例子:

Snackbar mSnackbar;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


final LinearLayout layout = findViewById(R.id.layout_main);
mSnackbar = Snackbar.make(layout, R.string.press_back_again, Snackbar.LENGTH_SHORT);
}


@Override
public void onBackPressed() {
if (mSnackbar.isShown()) {
super.onBackPressed();
} else {
mSnackbar.show();
}
}

下面是完整的工作代码。并且不要忘记删除回调,这样它就不会在应用程序中导致内存泄漏:)

private boolean backPressedOnce = false;
private Handler statusUpdateHandler;
private Runnable statusUpdateRunnable;


public void onBackPressed() {
if (backPressedOnce) {
finish();
}


backPressedOnce = true;
final Toast toast = Toast.makeText(this, "Press again to exit", Toast.LENGTH_SHORT);
toast.show();


statusUpdateRunnable = new Runnable() {
@Override
public void run() {
backPressedOnce = false;
toast.cancel();  //Removes the toast after the exit.
}
};


statusUpdateHandler.postDelayed(statusUpdateRunnable, 2000);
}


@Override
protected void onDestroy() {
super.onDestroy();
if (statusUpdateHandler != null) {
statusUpdateHandler.removeCallbacks(statusUpdateRunnable);
}
}

这是被接受和投票最多的回应,但这个片段用了Snackbar而不是Toast。

boolean doubleBackToExitPressedOnce = false;


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


this.doubleBackToExitPressedOnce = true;
Snackbar.make(content, "Please click BACK again to exit", Snackbar.LENGTH_SHORT)
.setAction("Action", null).show();




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


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

在我的例子中,我依赖Snackbar#isShown()来获得更好的UX

private Snackbar exitSnackBar;


@Override
public void onBackPressed() {
if (isNavDrawerOpen()) {
closeNavDrawer();
} else if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
if (exitSnackBar != null && exitSnackBar.isShown()) {
super.onBackPressed();
} else {
exitSnackBar = Snackbar.make(
binding.getRoot(),
R.string.navigation_exit,
2000
);
exitSnackBar.show();
}
} else {
super.onBackPressed();
}
}

对于具有导航的抽屉里的活动,使用下面的OnBackPressed()代码

boolean doubleBackToExitPressedOnce = false;


@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
if (doubleBackToExitPressedOnce) {
if (getFragmentManager().getBackStackEntryCount() ==0) {
finishAffinity();
System.exit(0);
} else {
getFragmentManager().popBackStackImmediate();
}
return;
}


if (getFragmentManager().getBackStackEntryCount() ==0) {
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);
} else {
getFragmentManager().popBackStackImmediate();
}
}
}

在这里,我已经概括编写了N个点击计数的代码。代码类似地为android设备中的启用开发人员选项编写。甚至你可以在开发人员测试应用程序时使用它来启用功能。

 private Handler tapHandler;
private Runnable tapRunnable;
private int mTapCount = 0;
private int milSecDealy = 2000;


onCreate(){
...
tapHandler = new Handler(Looper.getMainLooper());


}

在backpress或logout选项上调用askToExit()

private void askToExit() {
if (mTapCount >= 2) {
releaseTapValues();
/* ========= Exit = TRUE  =========  */
}


mTapCount++;
validateTapCount();
}




/* Check with null to avoid create multiple instances of the runnable */
private void validateTapCount() {
if (tapRunnable == null) {
tapRunnable = new Runnable() {
@Override
public void run() {
releaseTapValues();
/* ========= Exit = FALSE  =========  */
}
};
tapHandler.postDelayed(tapRunnable, milSecDealy);
}
}


private void releaseTapValues() {
/* Relase the value  */
if (tapHandler != null) {
tapHandler.removeCallbacks(tapRunnable);
tapRunnable = null; /* release the object */
mTapCount = 0; /* release the value */
}
}




@Override
protected void onDestroy() {
super.onDestroy();
releaseTapValues();
}

我用这个

import android.app.Activity;
import android.support.annotation.StringRes;
import android.widget.Toast;


public class ExitApp {


private static long lastClickTime;


public static void now(Activity ctx, @StringRes int message) {
now(ctx, ctx.getString(message), 2500);
}


public static void now(Activity ctx, @StringRes int message, long time) {
now(ctx, ctx.getString(message), time);
}


public static void now(Activity ctx, String message, long time) {
if (ctx != null && !message.isEmpty() && time != 0) {
if (lastClickTime + time > System.currentTimeMillis()) {
ctx.finish();
} else {
Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show();
lastClickTime = System.currentTimeMillis();
}
}
}


}

事件onBackPressed中的用它来

@Override
public void onBackPressed() {
ExitApp.now(this,"Press again for close");
}

ExitApp.now(this,R.string.double_back_pressed)

对于需要关闭的更改秒,指定毫秒

ExitApp.now(this,R.string.double_back_pressed,5000)

当HomeActivity包含导航抽屉和双backPressed()函数退出应用程序。 (不要忘记初始化全局变量布尔doubleBackToExitPressedOnce = false;) 将doubleBackPressedOnce变量设置为false

@Override
public void onBackPressed() {
DrawerLayout drawer = findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.END)) {
drawer.closeDrawer(GravityCompat.END);
} else {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
moveTaskToBack(true);
return;
} else {
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);
}
}
}

在java中

private Boolean exit = false;


if (exit) {
onBackPressed();
}

 @Override
public void onBackPressed() {
if (exit) {
finish(); // finish activity
} else {
Toast.makeText(this, "Press Back again to Exit.",
Toast.LENGTH_SHORT).show();
exit = true;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
exit = false;
}
}, 3 * 1000);


}
}

在芬兰湾的科特林

 private var exit = false


if (exit) {
onBackPressed()
}

 override fun onBackPressed(){
if (exit){
finish() // finish activity
}else{
Toast.makeText(this, "Press Back again to Exit.",
Toast.LENGTH_SHORT).show()
exit = true
Handler().postDelayed({ exit = false }, 3 * 1000)


}
}

在这种情况下,Snackbar是比Toast更好的选择来显示退出动作。下面是小吃店的工作方法。

@Override
public void onBackPressed() {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
Snackbar.make(this.getWindow().getDecorView().findViewById(android.R.id.content), "Please click BACK again to exit", Snackbar.LENGTH_SHORT).show();


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


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

还有另一种方法……使用CountDownTimer方法

private boolean exit = false;
@Override
public void onBackPressed() {
if (exit) {
finish();
} else {
Toast.makeText(this, "Press back again to exit",
Toast.LENGTH_SHORT).show();
exit = true;
new CountDownTimer(3000,1000) {


@Override
public void onTick(long l) {


}


@Override
public void onFinish() {
exit = false;
}
}.start();
}


}

在不得不多次实现相同的东西之后,决定是时候建立一个简单易用的库了。那就是DoubleBackPress Android libraryREADME解释了随示例一起提供的所有api(如ToastDisplay +退出活动),但这里有一个简短的步骤纲要。


首先,将dependency添加到应用程序中:

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

接下来,在你的Activity中创建一个DoubleBackPress对象,它提供所需的行为。

DoubleBackPress doubleBackPress = new DoubleBackPress();
doubleBackPress.setDoublePressDuration(3000);           // msec

然后创建一个需要在第一次背压上显示的Toast。在这里,你可以创建自己的Toast,或者使用library. xml文件中提供的Standard Toast。通过后面的选项来实现。

FirstBackPressAction firstBackPressAction = new ToastDisplay().standard(this);
doubleBackPress.setFirstBackPressAction(firstBackPressAction);   // set the action

现在,定义当你第二次背推发生时应该发生什么。在这里,我们正在关闭Activity。

DoubleBackPressAction doubleBackPressAction = new DoubleBackPressAction() {
@Override
public void actionCall() {
finish();
System.exit(0);
}
};

最后,用DoubleBackPress行为覆盖你的背压行为。

@Override
public void onBackPressed() {
doubleBackPress.onBackPressed();
}

类似行为要求的GIF示例

 private static final int TIME_DELAY = 2000;
private static long back_pressed;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void onBackPressed() {
if (back_pressed + TIME_DELAY > System.currentTimeMillis()) {
super.onBackPressed();
} else {
Toast.makeText(getBaseContext(), "Press once again to exit!",
Toast.LENGTH_SHORT).show();
}
back_pressed = System.currentTimeMillis();
}

你甚至可以让它更简单,不使用hander,只这样做=)

Long firstClick = 1L;
Long secondClick = 0L;


@Override
public void onBackPressed() {
secondClick = System.currentTimeMillis();
if ((secondClick - firstClick) / 1000 < 2) {
super.onBackPressed();
} else {
firstClick = System.currentTimeMillis();
Toast.makeText(MainActivity.this, "click BACK again to exit", Toast.LENGTH_SHORT).show();
}
}

你也可以使用Toast的可见性,所以你不需要Handler/postDelayed超解决方案。

Toast doubleBackButtonToast;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


doubleBackButtonToast = Toast.makeText(this, "Double tap back to exit.", Toast.LENGTH_SHORT);
}


@Override
public void onBackPressed() {
if (doubleBackButtonToast.getView().isShown()) {
super.onBackPressed();
}


doubleBackButtonToast.show();
}
private static final int TIME_INTERVAL = 2000;
private long mBackPressed;
@Override
public void onBackPressed() {


if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis()) {
super.onBackPressed();
Intent intent = new Intent(FirstpageActivity.this,
HomepageActivity.class);
startActivity(intent);
finish();


return;
} else {


Toast.makeText(getBaseContext(),
"Tap back button twice  to go Home.", Toast.LENGTH_SHORT)
.show();


mBackPressed = System.currentTimeMillis();


}


}

在Kotlin的背面按下退出应用程序,你可以使用:

定义一个全局变量:

private var doubleBackToExitPressedOnce = false

覆盖onBackPressed:

override fun onBackPressed() {
if (doubleBackToExitPressedOnce) {
super.onBackPressed()
return
}


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


Handler().postDelayed({
doubleBackToExitPressedOnce = false;
}, 2000)
}
我通常会加一条评论,但我的声誉不允许这样做。 下面是我的观点:

在Kotlin中,你可以使用协程来延迟设置为false:

private var doubleBackPressed = false
private var toast : Toast ?= null


override fun onCreate(savedInstanceState: Bundle?) {
toast = Toast.maketext(this, "Press back again to exit", Toast.LENGTH_SHORT)
}


override fun onBackPressed() {
if (doubleBackPressed) {
toast?.cancel()
super.onBackPressed()
return
}
this.doubleBackPressed = true
toast?.show()
GlobalScope.launch {
delay(2000)
doubleBackPressed = false
}
}

你必须输入:

import kotlinx.coroutines.launch
import kotlinx.coroutines.delay
import kotlinx.coroutines.GlobalScope

以下是我的看法:

 int oddeven = 0;
long backBtnPressed1;
long backBtnPressed2;
@Override
public void onBackPressed() {
oddeven++;
if(oddeven%2==0){
backBtnPressed2 = System.currentTimeMillis();
if(backBtnPressed2-backBtnPressed1<2000) {
super.onBackPressed();
return;
}
}
else if(oddeven%2==1) {
backBtnPressed1 = System.currentTimeMillis();
//  Insert toast back button here
}
}

下面是一种使用RxJava的方法:

override fun onCreate(...) {
backPresses.timeInterval(TimeUnit.MILLISECONDS, Schedulers.io())
.skip(1) //Skip initial event; delay will be 0.
.onMain()
.subscribe {
if (it.time() < 7000) super.onBackPressed() //7000 is the duration of a Toast with length LENGTH_LONG.
}.addTo(compositeDisposable)


backPresses.throttleFirst(7000, TimeUnit.MILLISECONDS, Schedulers.io())
.subscribe { Toast.makeText(this, "Press back again to exit.", LENGTH_LONG).show() }
.addTo(compositeDisposable)
}


override fun onBackPressed() = backPresses.onNext(Unit)

按键2次返回

public void click(View view){
if (isBackActivated) {
this.finish();
}
if (!isBackActivated) {
isBackActivated = true;
Toast.makeText(getApplicationContext(), "Again", Toast.LENGTH_SHORT).show();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
isBackActivated = false;  // setting isBackActivated after 2 second
}
}, 2000);
}


}

吐司的最佳解决方案

在Java中

private Toast exitToast;


@Override
public void onBackPressed() {
if (exitToast == null || exitToast.getView() == null || exitToast.getView().getWindowToken() == null) {
exitToast = Toast.makeText(this, "Press again to exit", Toast.LENGTH_LONG);
exitToast.show();
} else {
exitToast.cancel();
super.onBackPressed();
}
}

在芬兰湾的科特林

private var exitToast: Toast? = null


override fun onBackPressed() {
if (exitToast == null || exitToast!!.view == null || exitToast!!.view.windowToken == null) {
exitToast = Toast.makeText(this, "Press again to exit", Toast.LENGTH_LONG)
exitToast!!.show()
} else {
exitToast!!.cancel()
super.onBackPressed()
}
}

我认为这是你需要的,我的意思是当我们想要显示这个吐司时,当堆栈中只有一个活动并且用户返回时来自堆栈的最后一个活动。

var exitOpened=false // Declare it globaly

并在onBackPressed方法中将其更改为:

override fun onBackPressed() {
if (isTaskRoot && !exitOpened)
{
exitOpened=true
toast("Please press back again to exit")
return
}
super.onBackPressed()
}

在这里,如果当前活动是堆栈的根活动(第一个活动)isTaskRoot将返回true,如果不是则返回false。

你可以查看官方文档在这里

我已经尝试为此创建了一个utils类,因此任何活动或片段都可以实现这一点,从而变得更简单。

代码是用Kotlin &还有java互操作。

我使用协程来延迟和重置标志变量。但是您可以根据自己的需要进行修改。

附加文件: SafeToast.kt

lateinit var toast: Toast


fun Context.safeToast(msg: String, length: Int = Toast.LENGTH_LONG, action: (Context) -> Toast = default) {
toast = SafeToast.makeText(this@safeToast, msg, length).apply {
// do anything new here
action(this@safeToast)
show()
}
}


fun Context.toastSpammable(msg: String) {
cancel()
safeToast(msg, Toast.LENGTH_SHORT)
}


fun Fragment.toastSpammable(msg: String) {
cancel()
requireContext().safeToast(msg, Toast.LENGTH_SHORT)
}


private val default: (Context) -> Toast = { it -> SafeToast.makeText(it, "", Toast.LENGTH_LONG) }


private fun cancel() {
if (::toast.isInitialized) toast.cancel()
}

ActivityUtils.kt

@file:JvmMultifileClass
@file:JvmName("ActivityUtils")
package your.company.com


import android.app.Activity
import your.company.com.R
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch




private var backButtonPressedTwice = false


fun Activity.onBackPressedTwiceFinish() {
onBackPressedTwiceFinish(getString(R.string.msg_back_pressed_to_exit), 2000)
}


fun Activity.onBackPressedTwiceFinish(@StringRes message: Int, time: Long) {
onBackPressedTwiceFinish(getString(message), time)
}


fun Activity.onBackPressedTwiceFinish(message: String, time: Long) {
if (backButtonPressedTwice) {
onBackPressed()
} else {
backButtonPressedTwice = true
toastSpammable(message)
GlobalScope.launch {
delay(time)
backButtonPressedTwice = false
}
}
}

Kotlin中的用法

// ActivityA.kt
override fun onBackPressed() {
onBackPressedTwiceFinish()
}

在Java中使用

@Override
public void onBackPressed() {
ActivityUtils.onBackPressedTwiceFinish()
}

此代码的灵感来自@webserveis 在这里

这个解决方案的独特之处在于行为;其中,非双击将显示吐司和成功双击将显示没有吐司,同时关闭应用程序。 唯一的缺点是吐司的显示将有650毫秒的延迟。我相信这是最佳行为的最佳解决方案,因为逻辑表明,如果没有这样的延迟,就不可能有这种行为

//App Closing Vars
private var doubleBackPressedInterval: Long = 650
private var doubleTap = false
private var pressCount = 0
private var timeLimit: Long = 0


override fun onBackPressed() {
pressCount++
if(pressCount == 1) {
timeLimit = System.currentTimeMillis() + doubleBackPressedInterval
if(!doubleTap) {
showExitInstructions()
}
}
if(pressCount == 2) {
if(timeLimit > System.currentTimeMillis()) {
doubleTap = true
super.onBackPressed()
}
else {
showExitInstructions()
}
pressCount = 1
timeLimit = System.currentTimeMillis() + doubleBackPressedInterval
}
}


private fun showExitInstructions() {
Handler().postDelayed({
if(!doubleTap) {
Toast.makeText(this, "Try Agian", Toast.LENGTH_SHORT).show()
}
}, doubleBackPressedInterval)
}

答案很容易使用,但我们需要双击退出。我只是修改了答案,

    @Override
public void onBackPressed() {
++k;
if(k==1){
Toast.makeText(this, "Press back one more time to exit", Toast.LENGTH_SHORT).show();
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
--k;
}
},1000);
}else{
//do whatever you want to do on the click after the first for example:
finishAffinity();
}
}

大多数现代应用程序只使用一个活动和多个片段。所以如果你在使用导航组件并且需要从home片段调用实现,这是解决方案。

override fun onAttach(context: Context) {
super.onAttach(context)
val callback: OnBackPressedCallback = object :
OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (doubleBackPressed) {
activity.finishAffinity()
}
doubleBackPressed = true
Toast.makeText(requireActivity(), "Press BACK again to exit", Toast.LENGTH_LONG).show()
Handler(Looper.myLooper()!!).postDelayed(Runnable {doubleBackPressed = false},
2000)
}
}
requireActivity().onBackPressedDispatcher.addCallback(this, callback)
}