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

我想知道,正如我越来越经常看到的那样,这是您可以在活动中以某种方式访问​​的内置功能吗?我看过许多类的源代码,但似乎找不到任何东西。

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

编辑:正如@LAS_VEGAS所述,我没有它在传统意义上确实意味着“退出”。 (即终止),如果可以的话,我的意思是“返回到启动应用程序启动活动之前打开的所有内容” :)

评论

[Android-确认吐司退出应用] [1]:stackoverflow.com/questions/14006461/…

使用HoloEverywhere库时,我遇到了同样的问题,太简单了,您可以在清单文件中的活动定义中添加android:launchMode =“ singleTask”。

其他解决方案stackoverflow.com/questions/8430805/…

重复两次单击android back按钮可能会退出应用程序

#1 楼


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



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


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

评论


最佳答案!您还可以添加条件if(doubleBackToExitPressedOnce || fragmentManager.getBackStackEntryCount()!= 0){如果是基于片段的添加

– Anton Derevyanko
2012-12-12 10:47



我同意,这绝对是最佳答案,应该是公认的答案。

–BruceHill
13年2月24日在18:27

退出应用程序时,应删除Runnable。

–韦恩
13年4月22日在10:05

检查我的答案。我已经修改了Sudheesh B Nair给出的答案,以涵盖上面建议的评论。

–穆勒·乔伊斯(Mehul Joisar)
2014年2月3日在7:46

这是一个很好的快速解决方案/答案,但我不同意这是最好的解决方案。对于那些认为这将是最佳答案的人,我不同意。这些解决方案会导致泄漏,并且需要额外的精力进行处理。请查看下面的查询,以获取更多详细信息。

– SaroTaşciyan
2014年4月27日上午10:57

#2 楼

Sudheesh B Nair在这个问题上有一个不错的(并且被接受)答案,我认为应该有一个更好的选择,例如;

测量经过的时间并检查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一起声明为成员。然后可以适当地调用removeCallbacks()Handler方法。

以下示例为演示;

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-并可以在调用mExitToast.cancel();之前通过super.onBackPressed();取消它。

评论


对于那些认为Sudheesh B Nair所说的是相同的人:相同的功能,更好的性能。所以+1。

– BedirYilmaz
2014年3月11日17:52

我喜欢这个答案,我认为这是最好的。我的意思是我不认为这是最佳答案,因为上述原因。希望您对此有更多的支持。不过有一条评论:没有人发现在应用程序关闭后烤面包持续了几秒钟是一件奇怪的事吗?没人愿意取消敬酒吗?我知道这可能是一个很小的细节,但我认为这应该发生。你们有什么感想?

–英亩
2014年7月1日在21:32

@joonty感谢您的编辑,该int关键字已丢失了一段时间。它将立即编译(:

– SaroTaşciyan
14-10-17在6:50

@NSouth第二个代码块是使用mHandlers的示例,以显示它需要更多的精力。我建议您考虑使用第一个不使用处理程序的代码块。

– SaroTaşciyan
15年4月24日在7:26

@acrespo我想我们有一个可靠的解决方案,可在应用程序关闭后继续保留吐司消息。

– SaroTaşciyan
2015年5月6日19:15

#3 楼

只是以为我会分享我最终做的事情,所以我在活动中添加了一个内容:

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


它完全可以按照我的要求工作。每当恢复活动时都包括重置状态。

评论


通过这种解决方案,两个后推之间的时间可以是任意的。因此,您可以按一次Back,然后在一分钟后再次按Back,应用程序将退出。这不是用户期望的行为。

–BruceHill
13年2月24日在18:26

我认为这是一个品味问题。在这种情况下,您仅通知用户一次,因此用户知道他正在参加主要活动,并且另一次按下将退出应用程序(可能是在用户按下两次返回主屏幕之后)。如果以后用户再次按下该按钮,我们可以假设他要退出该应用程序(除非他已经导航到其他活动并且可能无法跟踪自己的深度)。在上面接受的答案中,您认为用户可能会忘记他已经在主屏幕中。两者都很好,取决于您想要或考虑什么。

– Ferran Maylinch
2014年2月20日在12:47



@FerranMaylinch-我不同意。这不仅仅是品味问题。如果已经过了很长时间,我们应该假设用户在此期间做了其​​他操作,并且不再考虑自己以前所做的事情,选择不再继续申请。确实,除了最出色的用户以外,所有用户甚至都不会想到自己以前曾经这样做过。没有时间限制,您使应用程序处于用户无法了解的隐形模式。我绝对认为这是糟糕的用户界面设计。用户会感到惊讶。

–ToolmakerSteve
16-09-22在10:45



恕我直言,这里和这里的更好的变体。

–ToolmakerSteve
16-09-22在10:48

#4 楼

流程图:


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


评论


我最初将其投票为有帮助。麻烦是由于某种原因,这在某些手机上不起作用。 onBackPressed方法效果最好,但是您没有时间戳记,因此需要将处理程序作为接受的答案状态。

–ravemir
13年1月16日在10:04

#5 楼

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

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


您需要将back_pressed对象定义为活动中的long

#6 楼

您可以使用小吃店代替烤面包,因此您可以依靠它们的可见性来决定是否关闭应用程序。举个例子:
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();
    }
}


评论


感谢您的解决方案。简单,有效,无风险。

–平李
18年1月25日在23:07

开箱即用的解决方案。 (拍)

– Hitesh Dhamshaniya
18-2-14在10:25

#7 楼

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

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

}


希望对您有所帮助!

评论


您确定要在onBackPressed()中删除处理程序来解决内存泄漏问题吗?

– SaroTaşciyan
2015年9月8日在7:14

@Zefnus:据我所知它将修复。如果我错了,请纠正我。您如何跟踪上述代码的内存问题?

–穆勒·乔伊斯(Mehul Joisar)
2015年9月8日上午10:37

#8 楼

 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;


将其粘贴到您的主要活动中,这将解决您的问题


#9 楼

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

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按钮来退出应用程序。 br />

#10 楼

可接受的答案是最佳答案,但如果使用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);
    }


#11 楼

它不是内置功能。我认为这甚至不是推荐的行为。 Android应用程序不打算退出:

为什么Android应用程序不提供“退出”选项?

评论


点了。退出时,我的意思是“返回主屏幕”

–纪尧姆
2011年12月8日,12:14

它仍然不是内置功能。但是,我不知道有任何针对此的指南。作为Android用户,我喜欢这种功能。

– Caner
2011-12-8 12:26



#12 楼

Zefnus使用System.currentTimeMillis()的答案是最好的答案(+1)。我这样做的方法并没有比这更好,但是仍然将其发布以添加到上面的想法中。

如果按下后退按钮时看不见烤面包,则会显示烤面包,而如果可见(在上一次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();
   }
}


评论


是执行此操作的好方法,但是如果您有更多的吐司消息,则不是。

–波迪亚尔·保罗(Boldijar Paul)
2014年12月11日15:05

@BoldijarPaul不,此代码仅检查特定吐司的状态。因此,任何其他吐司都不会影响其行为。

–urgentx
19年1月16日在13:07

#13 楼


为MainActivity类声明一个全局Toast变量。示例:Toast exitToast;
在onCreate视图方法中将其初始化。示例:
exitToast = Toast.makeText(getApplicationContext(),“再次按下以退出”,Toast.LENGTH_SHORT);

最后创建一个onBackPressedMethod,如下所示:

@Override
public void onBackPressed() {

    if (exitToast.getView().isShown()) {
        exitToast.cancel();
        finish();
    } else {
        exitToast.show();
    }
}



我已经测试过,它可以正常工作。我认为这要简单得多。

#14 楼

最近,我需要在我的一个应用程序中实现此后退按钮功能。原始问题的答案很有用,但我还需要考虑两点:


在某些时间点,后退按钮被禁用了
主要活动正在结合使用片段和反向堆栈

基于答案和注释,我创建了以下代码:

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


上面的代码假定使用了支持库。如果使用片段但不使用支持库,则要将getSupportFragmentManager()替换为getFragmentManager()。如果从不取消后退按钮,请删除第一个if。删除第二个if,如果您不使用片段或片段返回堆栈

此外,请务必注意,自Android 2.0开始,支持onBackPressed方法。检查此页面以获得详细说明。要使后按功能也可以在旧版本上使用,请在您的活动中添加以下方法:

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


#15 楼

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

    }
}



在kotlin

 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)

        }
    }


#16 楼

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

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


我知道这不是最好的方法,但是工作正常!

评论


这不是“两次单击后退按钮以退出”的一般行为。就像BruceHill对已接受答案的评论指出的那样,您的答案也不能解决时间问题

– Berkuqo
13年4月21日在4:10

但是您可以单击此按钮,它会显示该消息,然后您可以等待一会儿,再次返回,它将关闭该应用程序,并且无法处理双向计时的行为。

–加斯顿·塞伦(GastónSaillén)
18/12/11在19:45

#17 楼

我通常会添加评论,但我的声誉不允许这样做。
这是我的两个美分:

在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


#18 楼

为此,我实现了以下功能:

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


#19 楼

我认为比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();
    }
}


#20 楼

当您将先前的堆栈活动存储在堆栈中时,这也有帮助。

我修改了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);
} 


#21 楼

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


评论


这甚至如何处理双击事件?一旦我回击,就会启动一个活动。

– kilokahn
18年1月19日在8:57

#22 楼

这是完整的工作代码。并且也不要忘记删除回调,以免引起应用程序内存泄漏。 :)

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


#23 楼

对于具有导航抽屉的活动,将以下代码用于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();
            }
        }
    }


#24 楼

在这里,我已概括地编写了N个抽头计数的代码。该代码类似地为android设备电话中的Enable Developer选项编写。即使在开发人员测试应用程序时,您也可以使用此功能来启用功能。

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

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

 }


在backpress或注销选项上调用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();
  }


#25 楼

我使用此

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)

#26 楼

当HomeActivity包含导航抽屉和double backPressed()函数退出应用程序时。
(不要忘记初始化全局变量boolean doubleBackToExitPressedOnce = false;)
2秒钟后,新处理程序将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);
        }
    }
}


#27 楼

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


#28 楼

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


#29 楼

这与已被接受并获得最多投票的答复相同,但是此消息被剥夺了,使用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);
    }


#30 楼

就我而言,我依靠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();
    }
}