활동을 종료하려면 뒤로 단추를 두 번 클릭하십시오.


330

최근 많은 Android 앱 및 게임에서이 패턴을 발견했습니다. 뒤로 버튼을 클릭하여 애플리케이션을 "종료"하면 "다시 다시 클릭하여 종료" Toast와 유사한 메시지가 나타납니다.

점점 더 자주 볼 수 있듯이 액티비티에서 어떻게 든 액세스 할 수있는 내장 기능입니까? 많은 클래스의 소스 코드를 살펴 보았지만 그것에 대해 아무것도 찾을 수없는 것 같습니다.

물론 동일한 기능을 매우 쉽게 달성 할 수있는 몇 가지 방법에 대해 생각할 수 있습니다 (가장 쉬운 것은 사용자가 이미 한 번 클릭했는지 여부를 나타내는 활동에 부울을 유지하는 것입니다 ...).하지만 이미 여기에 무언가가 있는지 궁금합니다. .

편집 : @LAS_VEGAS가 언급했듯이 나는 전통적인 의미에서 "종료"를 의미하지 않았습니다. (즉, 종료 됨) "응용 프로그램 시작 활동이 시작되기 전에 열려있는 모든 항목으로 돌아가는 것"을 의미했습니다.


[Android-토스트로 앱 종료 확인] [1] : stackoverflow.com/questions/14006461/…
resource8218

1
HoloEverywhere 라이브러리를 사용할 때도 동일한 문제가 발생했습니다. 매니페스트 파일의 활동 정의에 android : launchMode = "singleTask"를 추가하기 만하면됩니다.
Sohayb Hassoun


답변:


947

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

코 틀린 활동에서 :

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 초 후에 변수를 재설정하는 데 도움이된다고 생각합니다.


43
최고의 답변! (doubleBackToExitPressedOnce || fragmentManager.getBackStackEntryCount ()! = 0) {조각 기반 추가의 경우 조건을 추가 할 수도 있습니다.
Anton Derevyanko

2
동의합니다.이 답변은 가장 좋은 답변이며 허용되는 답변이어야합니다.
BruceHill

3
응용 프로그램을 종료 할 때 Runnable을 제거해야합니다.
Wayne

내 답변을 확인하십시오. Sudheesh B Nair . 위의 제안 의견을 다루기 위해 .
Mehul Joisar

18
좋은 빠른 솔루션 / 응답이지만 이것이 최고의 솔루션 이라는 데 동의 하지 않습니다 . 그리고 이것이 가장 좋은 대답 이라고 생각하는 사람들에게는 나는 동의 할 수 없습니다. 이 솔루션은 누출 을 유발 하며 취급을 위해 추가 노력이 필요합니다. 자세한 내용은 아래 aswers를 확인 하십시오.
Saro Taşciyan

226

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 년 말) 밀리 초 세트 - 리셋 경유 HandlerpostDelayed()방법은 내 마음에 와서 제일 먼저했다. 그러나 postDelayed()활동이 닫히면 작업을 취소하여을 (를) 제거해야합니다 Runnable.

을 제거하려면 익명Runnable 으로 선언해서는 안되며 또한 멤버와 함께 선언 해야합니다 . 그러면의 방법을 적절히 호출 할 수 있습니다.HandlerremoveCallbacks()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();.


9
Sudheesh B Nair의 말과 동일하다고 생각하는 사람들에게는 동일한 기능, 더 나은 성능. +1입니다.
BedirYilmaz

4
나는이 답변을 좋아하고 그것이 최고라고 생각합니다. 나는 그것이 위에서 언급 한 이유로 IT가 최선의 해결책이라고 생각하지 않습니다. 나는 당신이 이것에 대해 더 많은지지를 얻을 수 있기를 바랍니다. 그러나 한 가지 의견 : 아무도 앱이 닫힌 후 몇 초간 토스트가 지속되는 것이 이상하다고 생각하지 않습니까? 아무도 토스트를 취소하려고 신경 쓰지 않습니까? 나는 그것이 작은 세부 사항 일지 모른다는 것을 알고 있지만 그 일이 일어날 것이라고 생각합니다. 너희들은 어떻게 생각하니?
acrespo

1
@joonty 편집 해 주셔서 감사합니다. int 키워드가 얼마 동안 누락되었습니다. 그것은 지금 컴파일 할 것이다 (:
Saro Taşciyan

2
@NSouth Second 코드 블록은 더 많은 노력이 필요하다는 것을 보여주기 위해 mHandlers를 사용한 샘플이었습니다. 핸들러를 사용하지 않는 첫 번째 코드 블록을 사용하는 것이 좋습니다.
Saro Taşciyan

1
@acrespo 응용 프로그램을 닫은 후에도 지속되는 토스트 메시지를 위한 견고한 솔루션이 있다고 가정 합니다.
Saro Taşciyan

30

방금 마지막에 내가 한 일을 공유하겠다고 생각하고 방금 활동에 추가했습니다.

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

그리고 그것은 내가 원하는대로 정확하게 작동합니다. 활동이 재개 될 때마다 상태 재설정을 포함합니다.


15
이 솔루션을 사용하면 두 개의 백 프레스 사이에 임의의 시간이있을 수 있습니다. 누를 수 그래서 Back다음 번 누릅니다 Back분 후에 다시 응용 프로그램이 종료됩니다. 이것은 사용자가 기대하는 동작이 아닙니다.
BruceHill

1
나는 그것이 맛의 문제라고 생각합니다. 이 경우 사용자에게 한 번만 알리면 사용자가 자신이 주 활동에 있다는 것을 알 수 있고 다시 한 번 누르면 앱이 종료됩니다 (아마도 사용자가 몇 번 다시 메인 화면으로 돌아간 후). 나중에 사용자가 다시 답장을 보내면 다른 활동으로 이동하여 자신이 얼마나 깊었는지 추적하지 못한 경우가 아니라면 앱을 종료하려고한다고 가정 할 수 있습니다. 위의 답변에서 사용자는 이미 기본 화면에 있다는 것을 잊었을 수 있습니다. 당신이 원하거나 고려하는 것에 따라 둘 다 괜찮습니다.
Ferran Maylinch 12

4
@ FerranMaylinch-동의하지 않습니다. 이것은 단지 맛의 문제가 아닙니다. 상당한 시간이 경과하면, 우리는 해야 사용자가 그 동안 다른 작업을 수행했다고 가정하지 않고, 더 이상 그가 이전에 한 일을 생각 하고 계속하지 않기로 적용합니다. 실제로, 가장 뛰어난 사용자를 제외한 모든 사람들은 이전에 그렇게했다고 생각조차하지 않을 것입니다. 시간 제한 이 없으면 사용자가 알 방법이없는 보이지 않는 모드로 남겼습니다 . 나는 그것을 사용자 인터페이스 디자인이 열악하다고 생각합니다. 사용자는 놀라게 될 것입니다.
ToolmakerSteve

IMHO, 여기여기 에 더 나은 변형 .
ToolmakerSteve

26

공정 흐름도: 다시 누르면 종료됩니다.

자바 코드 :

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

1
나는 이것을 도움이되는 것으로 처음 투표했습니다. 문제는 어떤 이유로 일부 핸드셋에서는 작동하지 않습니다. onBackPressed 메소드가 가장 효과적이지만 타임 스탬프가 없으므로 허용되는 응답 상태로 핸들러가 필요합니다.
ravemir

23

이 모든 답변 중에서 가장 간단한 방법이 있습니다.

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.


16

스낵 바를 사용하는 솔루션 :

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

간단하고 세련된.


2
이 솔루션에 감사드립니다. 간단하고 효과적이며 위험이 없습니다.
ping li

2
기본 솔루션. (박수)
Hitesh Dhamshaniya

13

정답과 의견의 제안을 바탕으로, 절대적으로 잘 작동하고 사용 후 핸들러 콜백을 제거하는 데모를 만들었습니다.

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()해결하기 위해 처리기를 제거 하시겠습니까?
Saro Taşciyan

@ Zefnus : 내가 아는 한 고칠 것입니다. 내가 틀렸다면 나를 바로 잡으십시오. 위의 코드에서 메모리 문제를 어떻게 추적 했습니까?
Mehul Joisar

11
 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;

이것을 주요 활동에 붙여 넣으면 문제가 해결됩니다.


10

응용 프로그램을 종료 할 때 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 밀리 초인 특정 지연 시간 내에 더블 BACK 버튼 클릭으로 응용 프로그램을 종료하는 트릭을 수행합니다.


8

수락 된 답변은 최고 답변이지만 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);
    }

7

내장 기능이 아닙니다. 나는 그것이 권장되는 행동조차 아니라고 생각합니다. Android 앱은 종료하지 않습니다.

Android 애플리케이션이 "종료"옵션을 제공하지 않는 이유는 무엇입니까?


요점을 알았어. 나갈 때는 "홈 화면으로 돌아 가기"를 의미했습니다
Guillaume

3
여전히 내장 기능이 아닙니다. 그러나 나는 이것에 대한 지침을 모른다. 안드로이드 사용자로서 나는 그런 기능을 좋아합니다.
Caner

6
  1. MainActivity Class에 대한 전역 토스트 변수를 선언하십시오. 예 : 토스트 exitToast;
  2. onCreate보기 메소드에서 초기화하십시오. 예 : exitToast = Toast.makeText (getApplicationContext (), "다시 누르면 다시 종료", Toast.LENGTH_SHORT);
  3. 마지막으로 다음과 같이 onBackPressedMethod를 만듭니다.

    @Override
    public void onBackPressed() {
    
        if (exitToast.getView().isShown()) {
            exitToast.cancel();
            finish();
        } else {
            exitToast.show();
        }
    }

이것은 올바르게 작동합니다. 테스트했습니다. 저는 이것이 훨씬 간단하다고 생각합니다.


5

System.currentTimeMillis ()를 사용하는 Zefnus 의 답변이 가장 좋습니다 (+1). 내가 한 방식은 아닙니다 더 나은보다,하지만 여전히 위의 아이디어에 추가 게시.

Back (뒤로) 버튼을 누를 때 토스트가 보이지 않으면 토스트가 표시되는 반면, 마지막 (이전 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();
   }
}

1
이 작업을 수행하는 좋은 방법이지만 토스트 메시지가 더 많은 경우에는 그렇지 않습니다.
Boldijar Paul

@BoldijarPaul 아니요,이 코드는 해당 특정 토스트의 상태 만 확인합니다. 따라서 다른 건배는 행동에 영향을 미치지 않습니다.
urgentx

5

최근에 나는이 뒤로 버튼 기능을 내 앱에서 구현해야했습니다. 원래 질문에 대한 답변은 유용했지만 두 가지 점을 더 고려해야했습니다.

  1. 어떤 시점에서는 뒤로 버튼이 비활성화됩니다
  2. 주요 활동은 백 스택과 함께 조각을 사용하는 것입니다.

답변과 의견을 바탕으로 다음 코드를 작성했습니다.

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프래그먼트 또는 프래그먼트 백 스택을 사용하지 않는 경우

또한이 메소드 onBackPressed는 Android 2.0부터 지원 된다는 점에 유의해야합니다 . 자세한 설명은 이 페이지 를 확인하십시오 . 이전 버전에서도 역전 기능을 사용하려면 다음 방법을 활동에 추가하십시오.

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

5

자바에서

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

    }
}

코 틀린에서

 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)

        }
    }

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

이것이 최선의 방법은 아니지만 잘 작동한다는 것을 알고 있습니다!


3
"종료하려면 뒤로 단추를 두 번 클릭"하는 일반적인 동작이 아닙니다. 수락 된 답변에 대한 BruceHill의 의견과 마찬가지로, 귀하의 답변도 시간 문제를 처리하지 않습니다
inankupeli

하지만 당신은 메시지를 표시합니다, 다시 클릭하면 다음 다시 돌아가, 조금 더 이상 기다릴 수 있으며 응용 프로그램을 닫습니다, 그리고 두 번 다시 타이밍의 동작 처리하지 않습니다
가스통 Saillén

3

이를 위해 다음 기능을 구현했습니다.

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

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

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

1
이중 프레스 시나리오를 어떻게 처리합니까? 반격하자마자 활동이 시작됩니다.
kilokahn

2

제프 누스 보다 약간 더 나은 방법 이라고 생각합니다. 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();
    }
}

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

2

여기에서는 N 탭 수에 대한 코드 작성을 일반화했습니다. 코드는 안드로이드 장치 전화의 개발자 활성화 옵션과 유사하게 작성되었습니다. 개발자가 앱을 테스트하는 동안이 기능을 사용하여 기능을 활성화 할 수도 있습니다.

 private Handler tapHandler;
 private Runnable tapRunnable;
 private int mTapCount = 0;
 private int milSecDealy = 2000;

onCreate(){
 ...
tapHandler = new Handler(Looper.getMainLooper());

 }

뒤로 누르기 또는 로그 아웃 옵션에서 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();
  }

2

나는 이것을 사용한다

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)


2

HomeActivity에 탐색 창과 두 개의 backPressed () 함수가 포함되어 있으면 앱을 종료합니다. (글로벌 변수 boolean doubleBackToExitPressedOnce = false;를 초기화하는 것을 잊지 마십시오) 2 초 후 새 핸들러는 doubleBackPressedOnce 변수를 false로 설정합니다.

@Override
public void onBackPressed() {
    DrawerLayout drawer = findViewById(R.id.drawer_layout);
    if (drawer.isDrawerOpen(GravityCompat.END)) {
        drawer.closeDrawer(GravityCompat.END);
    } else {
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed();
            moveTaskToBack(true);
            return;
        } else {
            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);
        }
    }
}

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

1

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

1

이것은 가장 많이 받아 들여지고 투표 된 응답과 동일하지만 토스트 대신 스낵바를 사용했습니다.

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

1

제 경우에는 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();
    }
}

1

Navigation Drawer 가있는 활동의 경우 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();
            }
        }
    }

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

    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.