戻るボタンを2回クリックしてアクティビティを終了する


330

最近、多くのAndroidアプリやゲームでこのパターンに気づきました。「戻る」ボタンをクリックしてアプリケーションを「終了」すると、「Toast戻るにはもう一度クリックして終了してください」のようなメッセージが表示されます。

私はそれをますます目にしているので、アクティビティでなんとかしてアクセスできる組み込みの機能なのかと思っていました。私は多くのクラスのソースコードを見てきましたが、それについて何も見つけることができないようです。

もちろん、同じ機能を非常に簡単に実現するいくつかの方法を考えることができます(おそらく、ユーザーがすでに1回クリックしたかどうかを示すブール値をアクティビティに保持するのが最も簡単です...)が、ここにすでに何かあるかどうか疑問に思いました。

編集:@LAS_VEGASが述べたように、私は伝統的な意味での「終了」を本当に意味していませんでした。(つまり、終了した)意味がある場合は、「アプリケーション開始アクティビティが起動する前に開いていたものに戻る」ことを意味しました:)


[アンドロイド-トーストで確定アプリ出口] [1]:stackoverflow.com/questions/14006461/...
resource8218

1
HoloEverywhereライブラリを使用するときにも同じ問題がありましたが、マニフェストファイルのアクティビティ定義にandroid:launchMode = "singleTask"を追加するだけでもかまいません。
Sohayb Hassoun 2013


回答:


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

Kotlinアクティビティ:

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
ベストアンサー!if(doubleBackToExitPressedOnce || fragmentManager.getBackStackEntryCount()!= 0){フラグメントベースの追加の場合
Anton Derevyanko

2
これは間違いなく最良の答えであり、受け入れられる答えになるはずです。
BruceHill 2013

3
アプリケーションを終了するときにRunnableを削除する必要があります。
ウェイン、

私の回答を確認してくださいSudheesh B Nair。上記の提案されたコメントをカバーするために、によって与えられた回答を変更しました。
Mehul Joisar 14

18
これはすばやい解決策/回答ですが、それが最良の解決策であることに同意しません。そして、これが 再び最良の答えになると思う人たちには、同意できません。これらの解決策は漏れを引き起こし、取り扱いには追加の労力が必要になります。詳細については、以下の質問を確認してください。
SaroTaşciyan2014

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、をanonymousと宣言してはならず、また、としてメンバーとして宣言する必要がありますHandler。するとremoveCallbacks()メソッドof 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 14年

4
私はこの答えが好きで、最高だと思います。私はそれを考えていないと思います、それは上記の理由から、それが最良の答えです。これに賛成票をたくさん獲得してください ただし、コメントが1つあります。アプリが閉じてから数秒後にトーストが持続するのは奇妙なことです。誰もトーストをキャンセルしたくないですか?細かいことかもしれませんが、そうなると思います。皆さんはどう思いますか?
acrespo 2014

1
@joonty編集ありがとうございます、そのintキーワードはしばらくの間見当たりませんでした。今すぐコンパイルされます(:
SaroTaşciyan2014年

2
@NSouth 2番目のコードブロックは、より多くの労力が必要であることを示すためにmHandlersを使用したサンプルです。ハンドラーを使用しない最初のコードブロックの使用を検討することをお勧めします。
サロタチヤン2015

1
@acrespo アプリケーションが閉じた後もトーストメッセージが持続するための確かなソリューションがあると思います
SaroTaşciyan、2015年

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
このソリューションでは、2つのバックプレスの間に任意の時間を設定できます。したがって、Back一度押すBackと1分後にもう一度押すと、アプリケーションが終了します。これは、ユーザーが期待する動作ではありません。
BruceHill、2013

1
それは好みの問題だと思います。この場合、ユーザーに通知するのは1回だけなので、ユーザーがメインアクティビティにいることをユーザーに通知し、もう一度押してアプリを終了します(おそらくユーザーが何回か押してメイン画面に戻った後)。後でユーザーがもう一度押した場合、ユーザーがアプリを終了することを想定できます(別のアクティビティに移動し、おそらく深さを追跡できなくなった場合を除く)。上記の受け入れられた答えでは、ユーザーが自分がすでにメイン画面にいることを忘れている可能性があると考えています。どちらを使用するか、または何を検討するかによって、どちらも問題ありません。
Ferran Maylinch 2014

4
@FerranMaylinch-同意しません。これは単に好みの問題ではありません。かなりの時間が経過した場合、我々はすべきであるユーザーが、その間に他のアクションを行っていることを前提としない、もはや彼が以前にやったことと見なしとを継続しないことを選択した適用します。実際、最も例外的なユーザーを除くすべての人は、彼が以前にそれを行ったことをまだ心に留めていません。時間制限がないと、ユーザーが知る方法のない非表示モードでアプリが終了します。私はそれをユーザーインターフェースのデザインとしては良くないと思います。ユーザーは驚かれることでしょう。
ToolmakerSteve 2016

私見では、より良い、この上バリアントここここ
ToolmakerSteve 2016

26

プロセスフロー図: もう一度押すと終了します。

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

1
私は最初にこれが役に立ったと投票しました。問題は、いくつかの理由により、一部の携帯電話では機能しません。onBackPressedメソッドが最適に機能しますが、タイムスタンプがないため、受け入れられた回答の状態としてハンドラーが必要です。
ravemir 2013年

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 2018年

2
すぐに使えるソリューション。(拍手)
Hitesh Dhamshaniya 2018

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()修正するためにハンドラーを削除しますか?
SaroTaşciyan、2015

@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を使用するのは良い考えではありません。最近、2つの[戻る]ボタンをクリックする間の期間を記録して比較するはるかに簡単な方法を見つけました。以下のサンプルコード:

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ミリ秒である特定の遅延期間内に[戻る]ボタンを2回クリックしてアプリケーションを終了するトリックを実行します。


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
それでも、組み込みの機能ではありません。しかし、私はこれに対するガイドラインを知りません。Androidユーザーとして、私はそのような機能が好きです。
Caner

6
  1. MainActivityクラスのグローバルToast変数を宣言します。例:トースト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)です。私がやった方法はそれより良くありませんが、それでも投稿して上記のアイデアに追加します。

戻るボタンを押したときにトーストが表示されない場合はトーストが表示されますが、トーストが表示されている場合(前回のToast.LENGTH_SHORT時間内にすでに1回バックが押されている場合)は終了します。

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

最近、この戻るボタン機能を私のアプリに実装する必要がありました。元の質問に対する回答は役に立ちましたが、さらに2つの点を考慮する必要がありました。

  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フラグメントまたはフラグメントバックスタックを使用しない場合は、2番目を削除します。

また、このメソッド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

Javaで

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
これは、「戻るボタンを2回クリックして終了する」という一般的な動作ではありません。受け入れられた回答に関するBruceHillのコメントが指摘するように、あなたの回答も
時間の問題を

しかし、これであなたは、メッセージが表示されますは、[戻る]をクリックすることができ、その後、あなたは再び戻って、少し長く待つことができ、それはアプリを閉じて、それは二重のバックタイミングの振る舞いに処理しません
ガストン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
これはダブルプレスのシナリオをどのように処理しますか?私が反撃するとすぐに、これは活動を開始します。
キロカーン

2

Zefnusよりも少し良い方法だと思います。System.currentTimeMillis()を1回だけ呼び出し、省略し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タップカウントのコードを一般化して記述しました。コードは、Androidデバイス電話の「開発者を有効にする」オプション用に同様に記述されています。開発者がアプリをテストしているときに、これを使用して機能を有効にすることもできます。

 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の回答にいくつかの改善がありました。すぐに2回押してもハンドラーを待機することに気づいたので、以下に示すようにハンドラーをキャンセルします。アプリの終了後にトーストが表示されないようにするために、トーストをキャンセルしました。

 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

これは、受け入れられ、最も投票された応答と同じですが、この切り詰めはToastの代わりにSnackbarを使用しました。

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.