Нажав кнопку «Назад» дважды, чтобы выйти из игры - PullRequest
300 голосов
/ 08 декабря 2011

В последнее время я заметил эту закономерность во многих приложениях и играх для Android: при нажатии кнопки «Назад» для «выхода» из приложения появляется Toast с сообщением, похожим на «Пожалуйста, нажмите НАЗАД еще раз, чтобы выйти».

Мне было интересно, так как я вижу это все чаще и чаще, это встроенная функция, к которой вы можете как-то получить доступ в действии?Я просмотрел исходный код многих классов, но, похоже, ничего не могу найти по этому поводу.

Конечно, я могу придумать несколько способов довольно легко достичь той же функциональности (самый простойвероятно, для сохранения логического значения в действии, которое указывает, щелкнул ли пользователь уже один раз ...), но мне было интересно, есть ли здесь что-нибудь уже.на самом деле не означает «выход» в традиционном смысле.(то есть прекращено) Я имел в виду «возврат к тому, что было открыто до запуска операции запуска приложения», если это имеет смысл:)

Ответы [ 43 ]

857 голосов
/ 27 ноября 2012

В Java Activity:

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 Activity:

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 секунды.

208 голосов
/ 11 марта 2014

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) миллисекунд, и set - reset с помощью Handler, метод postDelayed() был первое, что пришло мне в голову. Но действие postDelayed() должно быть отменено, когда действие закрывается, удаляя Runnable.

Чтобы удалить Runnable, он не должен быть объявлен анонимным и должен быть объявлен как участник вместе с Handler aswell. Тогда 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();.

29 голосов
/ 09 декабря 2011

Просто подумал, что поделюсь, как я это сделал в конце, я просто добавил в свою деятельность:

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

И это работает именно так, как я хочу. Включая сброс состояния при возобновлении активности.

23 голосов
/ 29 декабря 2012

Технологическая схема: 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;
}
19 голосов
/ 24 мая 2014

Есть очень простой способ среди всех этих ответов.

Просто напишите следующий код внутри 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 в действии.

12 голосов
/ 03 февраля 2014

Основываясь на правильном ответе и предложениях в комментариях, я создал демо, которое работает абсолютно нормально и удаляет обратные вызовы обработчика после использования.

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

}

Надеюсь, это будет полезно !!

11 голосов
/ 07 января 2017

Мое решение с использованием закусочной:

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

Просто и стильно.

10 голосов
/ 13 мая 2015
 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 голосов
/ 21 января 2015

Не рекомендуется использовать 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 миллисекунд в выборке.

6 голосов
/ 08 декабря 2011

Это не встроенный функционал. Я думаю, что это даже не рекомендуемое поведение. Приложения Android не предназначены для выхода:

Почему приложения Android не предоставляют опцию «Выход»?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...