Android: Правильний спосіб використання onBackPress () з Toast


85

Я написав фрагмент коду, який дасть користувачеві підказку з проханням повторно натиснути, якщо вони хочуть вийти. На даний момент я працюю з кодом, але я знаю, що він написаний погано, і я припускаю, що є кращий спосіб це зробити. Будь-які пропозиції були б корисними!

Код:

public void onBackPressed(){
    backpress = (backpress + 1);
    Toast.makeText(getApplicationContext(), " Press Back again to Exit ", Toast.LENGTH_SHORT).show();

    if (backpress>1) {
        this.finish();
    }
}

5
Замінити this.finish()на super.onBackPressed();.
Фред,

5
замість того, щоб this.finish()скоріше зателефонувати, NavUtils.navigateUpFromSameTask(this);щоб повернутися до попереднього екрану / активності
до Кра

Відповіді:


213

Я б реалізував діалогове вікно із запитом у користувача, чи хоче він вийти, а потім зателефонував, super.onBackPressed()якщо хотів.

@Override
public void onBackPressed() {
    new AlertDialog.Builder(this)
        .setTitle("Really Exit?")
        .setMessage("Are you sure you want to exit?")
        .setNegativeButton(android.R.string.no, null)
        .setPositiveButton(android.R.string.yes, new OnClickListener() {

            public void onClick(DialogInterface arg0, int arg1) {
                WelcomeActivity.super.onBackPressed();
            }
        }).create().show();
}

У наведеному вище прикладі вам потрібно буде замінити WelcomeActivity на ім’я вашої діяльності.


це працює, але в моєму випадку спливаюче вікно відображається лише протягом декількох мілісекунд, а після зникнення відображається нове вікно. У мене немає часу натискати так чи ні, і якщо я його налагоджую, це не відповідає методу onClick. Чому?
Accollativo

4
@Accollativo, здається, у вас все ще є заклик до super.onBackPressed()вашого onBackPressed()визначення (крім того, що знаходиться всередині методу onClick)?
Steve Prentice

6
Кожен додаток, який я бачив, віддає перевагу методу "другого зворотного натискання". Користувач, випадково натиснувши клавішу "Назад", буде дратуватися, якщо з'явиться діалогове вікно. Тост менш нав'язливий.
Karmic Coder

@Steve Prentice Я використовую цей фрагмент у своєму додатку, але як бути, якщо у нас є запущений процес, коли ми підтримуємо свою діяльність - процес все ще працює. Як це виправити? Якщо я використовую, android.os.Process.killProcess(android.os.Process.myPid());але анімація між діями не така плавна. Замість цього він блимає чорним екраном приблизно половину секунди.
Станімір Якимов

1
@Stanimir Yakimov, вивчіть сервіси Android для запуску фонових процесів. Це полегшить вам управління життєвим циклом. Якщо ви все ще не можете зрозуміти, я пропоную створити нове запитання.
Steve Prentice

19

Вам не потрібен лічильник для зворотних пресів.

Просто збережіть посилання на показаний тост:

private Toast backtoast;

Тоді,

public void onBackPressed() {
    if(USER_IS_GOING_TO_EXIT) {
        if(backtoast!=null&&backtoast.getView().getWindowToken()!=null) {
            finish();
        } else {
            backtoast = Toast.makeText(this, "Press back to exit", Toast.LENGTH_SHORT);
            backtoast.show();
        }
    } else {
        //other stuff...
        super.onBackPressed();
    }
}

Це буде дзвонити, finish()якщо натиснути назад, поки тост все ще видно, і лише в тому випадку, якщо зворотне натискання призведе до виходу з програми.


замість того, щоб this.finish()скоріше зателефонувати, NavUtils.navigateUpFromSameTask(this);щоб повернутися до попереднього екрану / активності
до Кра

Альтернативний відповідь розглянути тут . Я ще не визначився, який підхід віддаю перевагу. Деякі деталі пов'язаної відповіді можуть бути додані до цієї, зокрема логіка скасування тосту, як тільки користувач виходить.
ToolmakerSteve

14

Я використовую набагато простіший підхід ...

public class XYZ extends Activity {
    private long backPressedTime = 0;    // used by onBackPressed()


    @Override
    public void onBackPressed() {        // to prevent irritating accidental logouts
        long t = System.currentTimeMillis();
        if (t - backPressedTime > 2000) {    // 2 secs
            backPressedTime = t;
            Toast.makeText(this, "Press back again to logout",
                                Toast.LENGTH_SHORT).show();
        } else {    // this guy is serious
            // clean up
            super.onBackPressed();       // bye
        }
    }
}

Щось дивне відбувається на планшеті Samsung Note. Потрібно швидко відбивати кілька разів. Йому також не подобається підхід "backToast" ...
SoloPilot

Чи краще це працює на Note, якщо ви скасуєте тост перед виходом? Дивіться це
ToolmakerSteve

2

Як ваш шлях, так і шлях @ Steve є прийнятними способами запобігти випадковим виїздам.

Якщо ви вирішите продовжити реалізацію, вам потрібно буде переконатись, що Timerзворотне натискання було ініціалізоване до 0, і, можливо, застосувати якийсь тип, щоб повернути його до 0 при натисканні клавіші після періоду перезарядки. (~ 5 секунд здається правильним)


2

Можливо, вам також доведеться скинути лічильник, onPauseщоб запобігти випадкам, коли користувач натискає додому або відходить якимось іншим способом після першого натискання назад. В іншому випадку я не бачу проблеми.


1

Якщо ви хочете вийти з прямої програми, не переходячи до програми Перша активність, спробуйте цей код

У Другий Діяльність поставте цей код ..

 @Override
public void onBackPressed() {
    new AlertDialog.Builder(this)
            .setTitle("Really Exit?")
            .setMessage("Are you sure you want to exit?")
            .setNegativeButton(android.R.string.no, null)
            .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {

                public void onClick(DialogInterface arg0, int arg1) {
                    setResult(RESULT_OK, new Intent().putExtra("EXIT", true));
                    finish();
                }

            }).create().show();
}

І ваша перша активність Помістіть цей код .....

public class FirstActivity extends AppCompatActivity {

Button next;
private final static int EXIT_CODE = 100;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    next = (Button) findViewById(R.id.next);
    next.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View view) {

            startActivityForResult(new Intent(FirstActivity.this, SecondActivity.class), EXIT_CODE);
        }
    });
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == EXIT_CODE) {
        if (resultCode == RESULT_OK) {
            if (data.getBooleanExtra("EXIT", true)) {
                finish();
            }
        }
    }
}

}


1

Це найкращий спосіб, тому що якщо користувач не повертається більше двох секунд, то скидає значення, яке було натиснуто назад.

оголосити одну глобальну змінну.

 private boolean backPressToExit = false;

onBackPressedМетод заміни .

@Override
public void onBackPressed() {

    if (backPressToExit) {
        super.onBackPressed();
        return;
    }
    this.backPressToExit = true;
    Snackbar.make(findViewById(R.id.yourview), getString(R.string.exit_msg), Snackbar.LENGTH_SHORT).show();
    new Handler().postDelayed(new Runnable() {

        @Override
        public void run() {
            backPressToExit = false;
        }
    }, 2000);
}

оголосити одну змінну ніби як приватна логічне backPressToExit = брехня
Йогеш Rathi

1) Будь ласка, відредагуйте свою відповідь, щоб включити логічну форму, яку ви згадали, замість того, щоб говорити про це у коментарі. Тож люди можуть побачити, де має бути декларація. 2) Справді, це альтернативний спосіб усвідомлення часу. Поясніть, будь ласка, чому ви вважаєте це "найкращим". Зокрема, це має накладні витрати на створення обробника - що виграє від цього?
ToolmakerSteve

0

крім того, перед викликом потрібно розіслати діалогове вікно activity.super.onBackPressed(), інакше ви отримаєте помилку "Активність витікла ..".

Приклад у моєму випадку з бібліотекою sweetalerdialog:

 @Override
    public void onBackPressed() {
        //super.onBackPressed();
        SweetAlertDialog progressDialog = new SweetAlertDialog(this, SweetAlertDialog.WARNING_TYPE);
        progressDialog.setCancelable(false);
        progressDialog.setTitleText("Are you sure you want to exit?");
        progressDialog.setCancelText("No");
        progressDialog.setConfirmText("Yes");
        progressDialog.setCanceledOnTouchOutside(true);
        progressDialog.setConfirmClickListener(new SweetAlertDialog.OnSweetClickListener() {
            @Override
            public void onClick(SweetAlertDialog sweetAlertDialog) {
                sweetAlertDialog.dismiss();
                MainActivity.super.onBackPressed();
            }
        });
        progressDialog.show();
    }

0

використовуйте для .onBackPress (), щоб повернути вказівку активності

@Override
public void onBackPressed(){
    backpress = (backpress + 1);
    Toast.makeText(getApplicationContext(), " Press Back again to Exit ", Toast.LENGTH_SHORT).show();

    if (backpress>1) {
        this.finish();
    }
}

1
Будь ласка, поясніть, що ви додали до оригінального коду, і чому.
ToolmakerSteve

0

Я просто мав цю проблему і вирішив її, додавши такий спосіб:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
             // click on 'up' button in the action bar, handle it here
             return true;

        default:
            return super.onOptionsItemSelected(item);
    }
}    

0

Ви також можете використовувати onBackPress, дотримуючись наступних способів, використовуючи індивідуальні Toast:

введіть тут опис зображення

customized_toast.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/txtMessage"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:drawableStart="@drawable/ic_white_exit_small"
    android:drawableLeft="@drawable/ic_white_exit_small"
    android:drawablePadding="8dp"
    android:paddingTop="8dp"
    android:paddingBottom="8dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:gravity="center"
    android:textColor="@android:color/white"
    android:textSize="16sp"
    android:text="Press BACK again to exit.."
    android:background="@drawable/curve_edittext"/>

MainActivity.java

@Override
public void onBackPressed() {

    if (doubleBackToExitPressedOnce) {
        android.os.Process.killProcess(Process.myPid());
        System.exit(1);
        return;
    }

    this.doubleBackToExitPressedOnce = true;
    Toast toast = new Toast(Dashboard.this);
    View view = getLayoutInflater().inflate(R.layout.toast_view,null);
    toast.setView(view);
    toast.setDuration(Toast.LENGTH_SHORT);
    int margin = getResources().getDimensionPixelSize(R.dimen.toast_vertical_margin);
    toast.setGravity(Gravity.BOTTOM | Gravity.CENTER_VERTICAL, 0, margin);
    toast.show();

    new Handler().postDelayed(new Runnable() {

        @Override
        public void run() {
            doubleBackToExitPressedOnce=false;
        }
    }, 2000);
}

0

Використовуйте це, це може допомогти.

@Override
public void onBackPressed() {
    new AlertDialog.Builder(this)
            .setTitle("Message")
            .setMessage("Do you want to exit app?")
            .setNegativeButton("NO", null)
            .setPositiveButton("YES", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    UserLogin.super.onBackPressed();
                }
            }).create().show();
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.