【问题标题】:Clicking the back button twice to exit an activity单击两次后退按钮以退出活动
【发布时间】:2012-01-15 21:05:13
【问题描述】:

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

我想知道,随着我越来越频繁地看到它,这是您可以在活动中以某种方式访问​​的内置功能吗?我查看了许多类的源代码,但似乎找不到任何相关内容。

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

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

【问题讨论】:

标签: java android back-button


【解决方案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();
        }

    }

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        Toast 的最佳解决方案

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

        在 Kotlin 中

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

        【讨论】:

        • my answer,只是晚了5年。也许您想对我的回答进行投票和评论? :)
        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

            【解决方案7】:

            在不得不多次实现相同的事情之后,决定是时候构建一个简单易用的库了。那是DoubleBackPress Android libraryREADME 解释了与示例一起提供的所有 API(如 ToastDisplay + Exit Activity),但这里只是简短的步骤。


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

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

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

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

            然后创建一个Toast,该Toast 需要在First Back Press 时显示。在这里,您可以创建自己的Toast,或使用library 中提供的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();
            }
            

            Example GIF of similar behavioural requirements

            【讨论】:

              【解决方案8】:
               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();
                  }
              

              【讨论】:

                【解决方案9】:

                你甚至可以让它更简单,不使用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();
                        }
                 }
                

                【讨论】:

                  【解决方案10】:

                  您还可以使用 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();
                  }
                  

                  【讨论】:

                    【解决方案11】:
                    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();
                    
                                }
                    
                            }
                    

                    【讨论】:

                      【解决方案12】:

                      这是我的看法:

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

                      【讨论】:

                      • 我试试这个我猜这是无泄漏的解决方案。
                      【解决方案13】:

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

                      【讨论】:

                        【解决方案14】:

                        按钮按下 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);
                            }
                        
                        }
                        

                        【讨论】:

                          【解决方案15】:

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

                          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。

                          可以查看官方文档here

                          【讨论】:

                            【解决方案16】:

                            我已经尝试为此创建一个 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 here

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 2015-02-06
                              • 2015-10-14
                              • 2015-11-29
                              • 1970-01-01
                              • 2018-08-21
                              • 1970-01-01
                              • 1970-01-01
                              相关资源
                              最近更新 更多