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

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

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

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


当前回答

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

其他回答

我认为这是最简单的方法

private static long exit;
@override
public void onBackPressed() {
    if (exit + 2000 > System.currentTimeMillis()) super.onBackPressed();
    else
        Toast.makeText(getBaseContext(), "Press once again to exit!", Toast.LENGTH_SHORT).show();
    exit = System.currentTimeMillis();
}

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

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

}

希望对大家有所帮助!!

我用这个

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(这个,R.string.double_back_pressed)

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

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

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

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

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

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