จะแสดงกล่องโต้ตอบเพื่อยืนยันว่าผู้ใช้ต้องการออกจากกิจกรรม Android ได้อย่างไร


274

ฉันพยายามแสดงข้อความ "คุณต้องการออกหรือไม่" ชนิดของกล่องโต้ตอบเมื่อผู้ใช้พยายามออกจากกิจกรรม

อย่างไรก็ตามฉันไม่พบ API hooks ที่เหมาะสม Activity.onUserLeaveHint()เริ่มแรกดูมีแนวโน้ม แต่ฉันไม่สามารถหาวิธีหยุดกิจกรรมจากการทำกิจกรรมให้เสร็จ


39
จำเป็นหรือไม่ที่คุณต้องมีพรอมต์นี้? เมื่อผู้ใช้ต้องการที่จะทำกิจกรรมให้เสร็จพวกเขาควรจะสามารถทำได้ทันที คุณอาจต้องการคิดใหม่กลยุทธ์ของคุณ
Tom R

4
การแสดงตัวเลือกการยืนยันการออกเป็นสิ่งจำเป็นสำหรับการจดทะเบียนที่ App Store ของ Samsung หนึ่งในแอพของฉันถูกปฏิเสธเนื่องจากไม่มีสิ่งนี้
John Ashmore

6
มันช่างน่ารังเกียจ @Samsung
dokkaebi

3
ขึ้นอยู่กับสิ่งที่คุณต้องการทำเมื่อออกจาก หากสถานะถูกเก็บรักษาไว้และคุณสามารถนำทางกลับไปได้การแสดงไดอะล็อกอาจไม่จำเป็น อย่างไรก็ตามในหนึ่งในแอปพลิเคชันของฉันฉันล้างคุกกี้ข้อมูลและการเชื่อมต่ออย่างใกล้ชิดเพื่อให้ได้ผลที่ดีด้วยการใช้ข้อมูลขั้นสุดท้าย ผู้ใช้ควรตระหนักถึงการตัดสินใจเลือกสุดท้ายของตนโดยเฉพาะอย่างยิ่งเนื่องจากเป็นเรื่องแปลกที่วันนี้จะมีความรู้สึกสุดท้ายในแอปพลิเคชันมือถือ
Eric

15
@ Tom R: ไม่เห็นด้วยอย่างสิ้นเชิง มีแอพที่คุณไม่ต้องการทำให้เสร็จโดยไม่ตั้งใจ พวกเขาทำงานในสภาพแวดล้อมทางธุรกิจและอื่น ๆ
TomeeNS

คำตอบ:


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 และสูงกว่ามีเหตุการณ์ onBackPressed ใหม่ที่ได้รับการแนะนำมากกว่านักพัฒนา onKeyDown.android.com/intl/zh-TW/reference/android/app/ ...... มีส่วนที่พูดถึงการเปลี่ยนแปลงและแนวทางที่แนะนำใหม่ developer.android.com/intl/zh-TW/sdk/android-2.0.html
Patrick Kafka

3
โพสต์บล็อกเกี่ยวกับการจับปุ่มย้อนกลับที่นี่: android-developers.blogspot.com/2009/12/… โปรดทราบว่านี่ไม่อนุญาตให้คุณจับวิธีอื่น ๆ ที่ผู้ใช้สามารถปล่อยให้แอปของคุณ: กดที่บ้านเลือกการแจ้งเตือนรับโทรศัพท์ โทร ฯลฯ
hackbod

สิ่งนี้ทำงานได้อย่างสมบูรณ์ แต่คุณบังคับให้การเรียกใช้โค้ดหยุดในขณะที่กำลังแสดงต่อผู้ใช้อย่างไร
anon58192932

พบว่านี่เป็นทางออกที่ยอดเยี่ยมที่นี่: stackoverflow.com/questions/4381296/…
anon58192932

1
นี่คือวิธีการ () สิ่งที่ฉันกำลังมองหา แต่ฉันไม่รู้ว่าจะเรียกวิธีนี้ได้ที่ใด
user2841300

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: การเรียก super onBackPressed ดีกว่าสมมติว่า onBackPressed จะโทรเสร็จเท่านั้น () แม้ว่านั่นจะเป็นจริงในตอนนี้ แต่ก็อาจไม่เป็นจริงใน API ในอนาคตCustomTabActivity.super.onBackPressed
mplungjan

@mplungjan คุณช่วยชี้แจงความคิดเห็นของคุณได้ ... คุณกำลังพูดว่าแทนที่finish()รหัสด้วยsuper.onBackPressed()หรือไม่
บ้านจีโอเอ็นจิเนียริ่ง

ความคิดเห็นมีอายุ 3 ปี ฉันไม่รู้เลยว่าการปฏิบัติที่ดีในปี 2015 คืออะไร
mplungjan

@mplungjan ความคิดเห็นของคุณอ้างอิงถึง API ในอนาคต แต่จะมีประโยชน์หากคุณสามารถชี้แจงได้
บ้านจีโอเอ็นจิเนียริ่ง

ไม่มีปัญหา. ฉันเพิ่งลองMyActivity.super.onBackPressed();และใช้งานได้ดีสำหรับฉัน ดูเหมือนว่าจะเป็นวิธีการที่มีเหตุผลมากที่สุดเช่นกัน - เรียกวิธีที่คุณเอาชนะถ้าคุณต้องการพฤติกรรมมาตรฐานเมื่อผู้ใช้แตะที่ "ไม่"
บ้านจีโอเอ็นจิเนียริ่ง

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


อันนี้เป็นที่ชื่นชอบของฉันแน่นอนเพราะกล่องโต้ตอบสามารถยุ่งยาก ฉันเปลี่ยนมันเล็กน้อยเพื่อให้มัน 3 วินาทีและดูเหมือนว่าเป็นธรรมชาติมากขึ้นด้วยเครื่องหมาย ขอบคุณสำหรับการโพสต์
PGMacDesign เมื่อ

ในแอพ Double back กดฉันควรออก แต่ในรหัสของฉันมันเปิดกิจกรรมเข้าสู่ระบบ (หมายถึงกิจกรรมที่เปิดใช้งานปินเนอร์)
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

การใช้แลมบ์ดา:

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

คุณต้องตั้งค่าภาษาระดับเพื่อรองรับ java 8 ใน gradle.build ของคุณ:

compileOptions {
       targetCompatibility 1.8
       sourceCompatibility 1.8
}

5

ในประเทศจีนแอพส่วนใหญ่จะยืนยันการออกโดย "คลิกสองครั้ง":

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 ปิดกิจกรรมปัจจุบันและจะแสดงกิจกรรมก่อนหน้านี้
shareef

1

อีกทางเลือกหนึ่งคือการแสดง a Toast/ Snackbarบน back back แรกที่ขอให้กด back อีกครั้งเพื่อออกซึ่งเป็นการรบกวนน้อยกว่าการแสดง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.