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

时间:2011-12-08 12:08:49

标签: java android back-button

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

我想知道,因为我越来越频繁地看到它是一个内置功能,你可以以某种方式访问​​活动?我查看了许多类的源代码,但我似乎无法找到任何相关内容。

当然,我可以考虑几种方法来轻松实现相同的功能(最简单的可能是在活动中保留一个布尔值,表明用户是否已经点击过一次......)但是我想知道是否有已有的东西。

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

43 个答案:

答案 0 :(得分:844)

  

在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秒后重置变量。

答案 1 :(得分:204)

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)毫秒内按下了设置 - 重置是通过Handler postDelayed()方法是我想到的第一件事。但是,当活动结束时,应取消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 message ,可以将Toast声明为成员 - 比如mExitToast - 并且可以通过mExitToast.cancel();取消就在super.onBackPressed();致电之前。

答案 2 :(得分:29)

想到我最后会分享我是如何做到的,我刚刚加入了我的活动:

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

它完全符合我的要求。包括在恢复活动时重置状态。

答案 3 :(得分:23)

流程图: Press again to exit.

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 :(得分:18)

所有这些答案中都有最简单的方法。

只需在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

答案 5 :(得分:12)

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

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

}

我希望它会有所帮助!!

答案 6 :(得分:11)

我使用snackbar的解决方案:

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

简单而时尚。

答案 7 :(得分:10)

 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;

  

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

答案 8 :(得分: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();
}

这样就可以通过双重BACK按钮在一定的延迟时间内点击退出应用程序,该延迟时间为2000毫秒。

答案 9 :(得分:6)

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

答案 10 :(得分:6)

  1. 为MainActivity Class声明一个全局Toast变量。示例:Toast exitToast;
  2. 在onCreate视图方法中初始化它。例:  exitToast = Toast.makeText(getApplicationContext(),&#34;再按一次退出&#34;,Toast.LENGTH_SHORT);
  3. 最后创建一个onBackPressedMethod作为Follows:

    @Override
    public void onBackPressed() {
    
        if (exitToast.getView().isShown()) {
            exitToast.cancel();
            finish();
        } else {
            exitToast.show();
        }
    }
    
  4. 这个工作正常,我已经测试过了。我认为这更简单。

答案 11 :(得分:6)

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

Why dont Android applications provide an "Exit" option?

答案 12 :(得分:5)

Zefnus使用System.currentTimeMillis()的答案是最好的(+1)。我这样做的方式是比这更好,但仍然发布它以增加上述想法。

如果按下后退按钮时看不到吐司,则显示吐司,而如果可见(后退已在最后Toast.LENGTH_SHORT时间内按下一次),则退出。 / p>

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

答案 13 :(得分:5)

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

  1. 在某些时间点,后退按钮被禁用
  2. 主要活动是将碎片与背堆组合使用
  3. 根据答案和评论,我创建了以下代码:

    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。请查看this page以获取详细说明。要使背压功能也适用于旧版本,请将以下方法添加到您的活动中:

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

答案 14 :(得分:4)

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

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

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

答案 15 :(得分:3)

在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 :(得分:3)

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

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

答案 17 :(得分:2)

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

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

答案 18 :(得分:2)

在这里,我已经概括地编写了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或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();
  }

答案 19 :(得分:2)

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

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

答案 20 :(得分:2)

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

答案 21 :(得分:1)

Sudheesh B Nair的答案中的一些改进,我注意到它会等待处理程序,即使在立即按下两次,所以取消处理程序,如下所示。我已经用tocled toast来阻止它在app退出后显示。

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

答案 22 :(得分:1)

此解决方案的独特之处在于行为;在关闭应用程序时,非双击将显示吐司,而成功双击将不显示吐司。 唯一的缺点是烤面包片的显示将有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)
}

答案 23 :(得分:1)

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

在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

答案 24 :(得分:1)

这是另一种方法......使用 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();
        }

    }

答案 25 :(得分:1)

在这种情况下,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);
        }

答案 26 :(得分:1)

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

答案 27 :(得分:1)

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

答案 28 :(得分:1)

这与已接受和最多投票的回复相同,但是使用了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);
    }

答案 29 :(得分:1)

对于具有导航抽屉的活动,请对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();
            }
        }
    }

答案 30 :(得分:1)

我用这个

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)

答案 31 :(得分:0)

在不得不多次执行相同的事情之后,决定了时间有人构建了一个简单易用的库。那是DoubleBackPress Android libraryREADME解释了随示例提供的所有API(例如ToastDisplay + Exit Activity),但这里的步骤简要介绍了。

要开始使用,请先将dependency添加到您的应用中:

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

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

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

然后创建一个需要在 First Back Press 上显示的Toast。在这里,您可以创建自己的Toast,或使用Standard Toast中提供的library。通过后面的选项在这里这样做。

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

现在,定义第二次背压发生时会发生什么。在这里,我们将关闭活动。

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

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

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

Example GIF of similar behavioural requirements

答案 32 :(得分:0)

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

答案 33 :(得分:0)

你甚至可以让它变得更简单,而且不使用汉德,只做这个=)

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

答案 34 :(得分:0)

您还可以使用Toast的可见性,因此您不需要Handler / postDelayed ultra解决方案。

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

答案 35 :(得分:0)

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

            }

        }

答案 36 :(得分:0)

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

答案 37 :(得分:0)

这是我的看法:

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

答案 38 :(得分:0)

这是使用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)

答案 39 :(得分:0)

按下两次按钮后返回

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

}

答案 40 :(得分:0)

吐司最佳解决方案

  

在Java中

final AlertDialog.Builder popDialog = new AlertDialog.Builder(getActivity());
popDialog.setTitle("Set Difficulty");
popDialog.setIcon(android.R.drawable.btn_star_big_on);

LinearLayout linearLayout = new LinearLayout(ExercisesActivity.this);
LinearLayout.LayoutParams lParams = new LinearLayout.LayoutParams(
        LinearLayout.LayoutParams.WRAP_CONTENT,
        LinearLayout.LayoutParams.WRAP_CONTENT
);

final RatingBar rating = new RatingBar(ExercisesActivity.this);
rating.setLayoutParams(lParams);
rating.setNumStars(6);
linearLayout.addView(rating);

popDialog.setView(linearLayout);

// Button OK
popDialog.setPositiveButton(android.R.string.ok,
    new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            //do things
        }
    });
popDialog.create();
popDialog.show();
  

在科特林

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

答案 41 :(得分:0)

我认为这是您所需要的,我的意思是当我们要显示此敬酒时,当堆栈中只有一个活动并且用户从堆栈中的最后一个活动中按回时。 >

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

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

您可以查看官方文档here

答案 42 :(得分:0)

我试图为此创建一个utils类,因此任何活动或片段都可以简化该实现。

该代码是用Kotlin编写的,并且还具有Java互操作性。

我正在使用协程延迟并重置flag变量。但是您可以根据需要进行修改。

其他文件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 here