单击后退button两次以退出活动
最近我在很多Android应用程序和游戏中注意到了这种模式:当点击后退button退出应用程序时, Toast
会出现类似于“请再次单击BACK退出”的消息。
当我越来越频繁地看到它时,我在想,是否可以通过某种方式访问活动中的内置function? 我看了很多类的源代码,但我似乎无法find任何有关的。
当然,我可以考虑几个方法来轻松实现相同的function(最简单的方法是在活动中保留一个布尔值,以指示用户是否已经点击过一次…),但是我想知道是否已经有一些东西在这里。
编辑 :作为@LAS_VEGAS提到,我并不是真正的意思是“退出”的传统意义。 (即终止)我的意思是“回到开始应用程序开始活动之前的任何事情”,如果这是有道理的:)
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); }
我认为这个处理程序有助于在2秒后重置该variables。
Sudheesh B Nair在这个问题上有一个很好的(也是可以接受的)答案,我认为应该有一个更好的select,比如:
测量时间已经过去了,并且检查自上次后按以来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()
方法设置 – 重置是我首先想到的。 但是当活动closures时, postDelayed()
操作应该被取消,移除Runnable
。
为了移除Runnable
,它不能被声明为匿名 ,并且与Handler
一起被声明为成员。 然后,可以适当地调用Handler
removeCallbacks()
方法。
下面的示例是示范;
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消息在应用程序closures后出现, Toast
可以被声明为一个成员 – 比如mExitToast
– 并且可以通过mExitToast.cancel();
来取消mExitToast.cancel();
只是在super.onBackPressed();
之前super.onBackPressed();
呼叫。
只是以为我会分享我到底做了些什么,我只是在我的活动中join了:
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(); }
它只是正如我所愿。 包括每当活动恢复时重置状态。
工艺stream程图:
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; }
基于正确的答案和意见build议,我创build了一个绝对正常的演示,并在使用后删除处理程序callback。
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()
方法中写下以下代码。
@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
对象。
在退出应用程序时使用Runnable并不是一个好主意,我最近想出了一个更简单的方法来logging和比较两个BACKbutton点击之间的时间间隔。 示例代码如下所示:
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毫秒的某个延迟时间内通过双击BACKbutton来退出应用程序。
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);
声明variables private boolean doubleBackToExitPressedOnce = false;
将其粘贴到您的主要活动中,这将解决您的问题
`
这不是一个内置的function。 我认为这甚至不是推荐的行为。 Android应用程序不打算退出:
为什么Android应用程序不提供“退出”选项?
我知道这是一个非常古老的问题,但这是做你想做的最简单的方法。
@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); }else{ //do whatever you want to do on the click after the first for example: finish(); } }
我知道这不是最好的方法,但它工作正常!
Zefnus使用System.currentTimeMillis()的答案是最好的(+1)。 我做的方式并不比这个更好,但是仍然发布它来增加上述想法。
如果在按下后退button时不显示吐司,则显示吐司,而如果可见(在最后的Toast.LENGTH_SHORT
时间内已经按下了一次),则退出。
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(); } }
最近,我需要在我的一个应用程序中实现这个后退buttonfunction。 原始问题的答案是有用的,但是我必须考虑两点:
- 在某些时候,后退button被禁用
- 主要的活动是使用碎片结合后退堆栈
根据答案和评论,我创build了以下代码:
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()
replacegetSupportFragmentManager()
getFragmentManager()
。
删除第一个,如果后退button从未取消。 如果不使用碎片或碎片堆栈,则删除第二个碎片
另外,请注意自Android 2.0以来支持onBackPressed
的方法是很重要的。 检查这个页面详细的描述。 为了使旧版本的function可以工作,请将以下方法添加到您的活动中:
@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); }
接受的答案是最好的,但如果你使用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); }
我的解决scheme使用小吃棒:
LinearLayout layout; Snackbar snackbar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); layout = (LinearLayout) findViewById(R.id.layout_main); snackbar = snackbar.make(layout, R.string.press_back_again, Snackbar.LENGTH_LONG); } @Override public void onBackPressed() { if (snackbar.isShown()) { super.onBackPressed(); } else { snackbar.show(); } }
@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); }
- 声明MainActivity类的全局Toastvariables。 例如:Toast exitToast;
- 在onCreate视图方法中初始化它。 例如:exitToast = Toast.makeText(getApplicationContext(),“再次按退出”,Toast.LENGTH_SHORT);
-
最后创build一个onBackPressedMethod如下:
@Override public void onBackPressed() { if (exitToast.getView().isShown()) { exitToast.cancel(); finish(); } else { exitToast.show(); } }
这工作正常,我已经testing。 我觉得这简单得多。
为此我已经实现了以下function:
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(); }
这是完整的工作代码。 也不要忘了删除callback,以免在应用程序中造成内存泄漏。 🙂
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); } }
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); }
当您将先前的堆栈活动存储在堆栈中时,这也有帮助。
我修改了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); }
这是接受和最多投票反应相同,但这削减了使用小吃,而不是吐司。
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(); } }
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); }
我认为比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(); } }
对于具有导航抽屉的活动,请对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(); } } }
int back = 1; @Override public void onBackPressed(){ if(back==2) { super.onBackPressed(); } else{ Toast.makeText(this,"Press back again to close",Toast.LENGTH_SHORT).show(); back++; } }
如果你想简单而不搞乱复杂的代码,试试这个方法。