ユーザーがAndroidアクティビティを終了することを確認するダイアログを表示する方法


274

「終了しますか?」を表示しようとしています。ユーザーがアクティビティを終了しようとしたときのダイアログのタイプ。

しかし、適切なAPIフックが見つかりません。 Activity.onUserLeaveHint()最初は有望に見えましたが、アクティビティの終了を止める方法が見つかりません。


39
このプロンプトがあることが絶対に必要ですか?ユーザーがアクティビティを完了したいときは、すぐに完了できる必要があります。あなたはあなたの戦略を再考したいと思うかもしれません。
トムR

4
SamsungのApp Storeに掲載するには、終了確認オプションの表示が必須です。これがないため、私のアプリの1つが拒​​否されました。
John Ashmore

6
@Samsungさん、これは不愉快です。
ドッカエビ

3
終了時に何をしたいかによります。状態が保持され、戻ることができる場合は、ダイアログを表示する必要がない場合があります。ただし、私のアプリケーションの1つでは、Cookie、データをクリーンアップして、データの最終コミットで接続を閉じています。特に今日のモバイルアプリケーションにそのような最終性の感覚を持つことは一般的でないため、ユーザーは選択の最終性を認識する必要があります。
エリック

15
@トムR:全くそう思わない。誤って終了したくないアプリがあります。彼らはビジネス環境などで働いています。
TomeeNS 2015

回答:


390

Android 2.0以降では、次のようになります。

@Override
public void onBackPressed() {
    new AlertDialog.Builder(this)
        .setIcon(android.R.drawable.ic_dialog_alert)
        .setTitle("Closing Activity")
        .setMessage("Are you sure you want to close this activity?")
        .setPositiveButton("Yes", new DialogInterface.OnClickListener()
    {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            finish();    
        }

    })
    .setNegativeButton("No", null)
    .show();
}

以前のバージョンでは、次のようになります。

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    //Handle the back button
    if(keyCode == KeyEvent.KEYCODE_BACK) {
        //Ask the user if they want to quit
        new AlertDialog.Builder(this)
        .setIcon(android.R.drawable.ic_dialog_alert)
        .setTitle(R.string.quit)
        .setMessage(R.string.really_quit)
        .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {

                //Stop the activity
                YourClass.this.finish();    
            }

        })
        .setNegativeButton(R.string.no, null)
        .show();

        return true;
    }
    else {
        return super.onKeyDown(keyCode, event);
    }

}

15
また、2.0以降では、onKeyDown developer.android.com/intl/zh-TW/reference/android/app/より も推奨される新しいonBackPressedイベント があります。変更と新しい推奨アプローチについて説明するセクションがここにあります。 developer.android.com/intl/zh-TW/sdk/android-2.0.html
Patrick Kafka

3
ここでバックキーをキャッチするブログの投稿: android-developers.blogspot.com/2009/12/… これは、ユーザーがアプリを離れることができる他の方法(ホームを押す、通知を選択する、電話を受け取る)をキャッチできないことに注意してください呼び出しなど
ハックボット2010

これは完全に機能しますが、ユーザーに表示されている間、コード実行を強制的に停止するにはどうすればよいですか?
anon58192932 2013年

それを見つけて、これはここで素晴らしいソリューションです:stackoverflow.com/questions/4381296/...
anon58192932

1
これは私が探しているmethod()ですが、このmethod()を呼び出す場所がわかりませんでした。
user2841300 2013

186
@Override
public void onBackPressed() {
    new AlertDialog.Builder(this)
           .setMessage("Are you sure you want to exit?")
           .setCancelable(false)
           .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                   ExampleActivity.super.onBackPressed();
               }
           })
           .setNegativeButton("No", null)
           .show();
}

5
elBradfordによるコメント:スーパーのonBackPressedの呼び出しは、onBackPressedがfinish()のみを呼び出すと想定するよりも優れています。それが今は正しいとしても、将来のAPIでは正しくない可能性がありますCustomTabActivity.super.onBackPressed
mplungjan

@mplungjanコメントを明確にできますか?finish()コードを置き換える方が良いと言っていますsuper.onBackPressed()か?
ban-geoengineering

コメントは3歳です。2015年の良い習慣は何なのか
わかり

@mplungjanあなたのコメントは将来のAPIを参照していましたが、とにかく明確にできると助かります。
ban-geoengineering 2015

問題ありません。まあ、私は試したところMyActivity.super.onBackPressed();、私にとってはうまくいきます。ユーザーが「いいえ」をタップしたときに標準の動作が必要な場合は、オーバーライドするメソッドを呼び出すのも最も論理的なアプローチのようです。
ban-geoengineering 2015

33

@ user919216コードを変更し、WebViewと互換性があるようにしました。

@Override
public void onBackPressed() {
    if (webview.canGoBack()) {
        webview.goBack();

    }
    else
    {
     AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Are you sure you want to exit?")
       .setCancelable(false)
       .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
                finish();
           }
       })
       .setNegativeButton("No", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
                dialog.cancel();
           }
       });
AlertDialog alert = builder.create();
alert.show();
    }

}

22

終了ダイアログを使用するよりも、戻るボタンをダブルタップして終了することをお勧めします。

このソリューションでは、最初に戻ったときにトーストが表示され、別のバックプレスがアプリを閉じることを警告します。この例では4秒未満です。

private Toast toast;
private long lastBackPressTime = 0;

@Override
public void onBackPressed() {
  if (this.lastBackPressTime < System.currentTimeMillis() - 4000) {
    toast = Toast.makeText(this, "Press back again to close this app", 4000);
    toast.show();
    this.lastBackPressTime = System.currentTimeMillis();
  } else {
    if (toast != null) {
    toast.cancel();
  }
  super.onBackPressed();
 }
}

トークン:http : //www.androiduipatterns.com/2011/03/back-button-behavior.html


Dialogboxは扱いにくいので、これは間違いなく私のお気に入りです。3秒にするために少し変更しましたが、そのマーカーでは少し自然に見えます。投稿ありがとうございます。
PGMacDesign

ダブルバックプレスで理想的にはアプリを終了する必要がありますが、コードではログインアクティビティを開きます(スピナーを有効にした状態でのバックアクティビティを意味します)
techDigi

21

「戻る」の呼び出しがアプリを終了するか、ユーザーを別のアクティビティに連れて行くかどうかわからない場合は、上記の答えをisTaskRoot()チェックでラップできます。これは、メインアクティビティをバックスタックに複数回追加できる場合、またはバックスタックの履歴を操作している場合に発生する可能性があります。

if(isTaskRoot()) {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage("Are you sure you want to exit?")
       .setCancelable(false)
       .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
                YourActivity.super.onBackPressed;
           }
       })
       .setNegativeButton("No", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
                dialog.cancel();
           }
       });
    AlertDialog alert = builder.create();
    alert.show();

} else {
    super.onBackPressed();
}

5

Lambdaの使用:

    new AlertDialog.Builder(this).setMessage(getString(R.string.exit_msg))
        .setTitle(getString(R.string.info))
        .setPositiveButton(getString(R.string.yes), (arg0, arg1) -> {
            moveTaskToBack(true);
            finish();
        })
        .setNegativeButton(getString(R.string.no), (arg0, arg1) -> {
        })
        .show();

また、gradle.buildでJava 8をサポートするためにレベル言語を設定する必要があります。

compileOptions {
       targetCompatibility 1.8
       sourceCompatibility 1.8
}

5

中国では、ほとんどのアプリは「2回クリック」して終了を確認します。

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

5

最初に、コードより下のコードsuper.onBackPressed();から削除しonbackPressed()ます。

@Override
public void onBackPressed() {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage("Are you sure you want to exit?")
           .setCancelable(false)
           .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                    MyActivity.this.finish();
               }
           })
           .setNegativeButton("No", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
               }
           });
    AlertDialog alert = builder.create();
    alert.show();

}

2

@GLeeアプローチが好きで、以下のようなフラグメントで使用します。

@Override
public void onBackPressed() {
    if(isTaskRoot()) {
        new ExitDialogFragment().show(getSupportFragmentManager(), null);
    } else {
        super.onBackPressed();
    }
}

フラグメントを使用したダイアログ:

public class ExitDialogFragment extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return new AlertDialog.Builder(getActivity())
            .setTitle(R.string.exit_question)
            .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    getActivity().finish();
                }
            })
            .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    getDialog().cancel();
                }
            })
            .create();
    }
}

2
Just put this code in your first activity 

@Override
    public void onBackPressed() {
        if (drawerLayout.isDrawerOpen(GravityCompat.END)) {
            drawerLayout.closeDrawer(GravityCompat.END);
        }
        else {
// if your using fragment then you can do this way
            int fragments = getSupportFragmentManager().getBackStackEntryCount();
            if (fragments == 1) {
new AlertDialog.Builder(this)
           .setMessage("Are you sure you want to exit?")
           .setCancelable(false)
           .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                    finish();
               }
           })
           .setNegativeButton("No", null)
           .show();


            } else {
                if (getFragmentManager().getBackStackEntryCount() > 1) {
                    getFragmentManager().popBackStack();
                } else {

           super.onBackPressed();
                }
            }
        }
    }

y最初のアクティビティ、中間のアクティビティに配置できません。jsutが現在のアクティビティを閉じて、前のアクティビティを表示しているからです
シャリーフ

1

もう1つの方法は、最初のバックプレスで/表示して、もう一度押してExitToastSnackbar戻るように要求するAlertDialogことです。

を使用するDoubleBackPress Android Libraryと、数行のコードでこれを実現できます。同様の動作を示すサンプルGIF。

まず、アプリケーションに依存関係を追加します。

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

次に、アクティビティで、必要な動作を実装します。

// set the Toast to be shown on FirstBackPress (ToastDisplay - builtin template)
// can be replaced by custom action (new FirstBackPressAction{...})
FirstBackPressAction firstBackPressAction = new ToastDisplay().standard(this);

// set the Action on DoubleBackPress
DoubleBackPressAction doubleBackPressAction = new DoubleBackPressAction() {
    @Override
    public void actionCall() {
        // TODO : Exit the application
        finish();
        System.exit(0);
    }
};

// setup DoubleBackPress behaviour : close the current Activity
DoubleBackPress doubleBackPress = new DoubleBackPress()
        .withDoublePressDuration(3000)     // msec - wait for second back press
        .withFirstBackPressAction(firstBackPressAction)
        .withDoubleBackPressAction(doubleBackPressAction);

最後に、これをバックプレスの動作として設定します。

@Override
public void onBackPressed() {
    doubleBackPress.onBackPressed();
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.