Android: Właściwy sposób używania onBackPressed () z Toast


85

Napisałem fragment kodu, który daje użytkownikowi monit, prosząc go o ponowne naciśnięcie, jeśli chcą wyjść. Obecnie mój kod w pewnym stopniu działa, ale wiem, że jest źle napisany i zakładam, że jest na to lepszy sposób. Wszelkie sugestie byłyby pomocne!

Kod:

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

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

5
Wymień this.finish()się super.onBackPressed();.
Fred

5
zamiast this.finish()dzwonić, NavUtils.navigateUpFromSameTask(this);aby wrócić do poprzedniego ekranu / aktywności
Do Kra

Odpowiedzi:


213

Zaimplementowałbym okno dialogowe z pytaniem użytkownika, czy chce wyjść, a następnie zadzwoniłbym, super.onBackPressed()gdyby to zrobił.

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

W powyższym przykładzie musisz zastąpić WelcomeActivity nazwą swojej aktywności.


to działa, ale w moim przypadku wyskakujące okienko jest wyświetlane tylko przez kilka milisekund, po czym znika i pojawia się nowe okno. Nie mam czasu, aby kliknąć tak lub nie, a jeśli go debuguję, nie przejdzie do metody onClick. Czemu?
Accollativo

4
@Accollativo, brzmi tak, jakbyś nadal miał wywołanie super.onBackPressed()w swojej onBackPressed()definicji (inne niż to w metodzie onClick)?
Steve Prentice

6
Każda aplikacja, którą widziałem, preferuje metodę „drugiego naciśnięcia wstecz”. Użytkownik, który przypadkowo naciśnie klawisz Wstecz, zdenerwuje się, jeśli pojawi się okno dialogowe. Toast jest mniej nachalny.
Karmic Coder

@Steve Prentice Używam tego fragmentu kodu w mojej aplikacji, ale co z tym, że mamy uruchomiony proces podczas tworzenia kopii zapasowej - proces nadal działa. Jak to naprawić? Jeśli używam, android.os.Process.killProcess(android.os.Process.myPid());ale animacja między czynnościami nie jest tak płynna. Zamiast tego miga czarnym ekranem przez około połowę sekundy.
Stanimir Yakimov

1
@Stanimir Yakimov, zapoznaj się z usługami Androida do uruchamiania procesów w tle. Ułatwi to zarządzanie cyklem życia. Jeśli nadal nie możesz tego rozgryźć, proponuję utworzyć nowe pytanie.
Steve Prentice

19

Nie potrzebujesz licznika do back pressów.

Po prostu zapisz odniesienie do pokazanego toastu:

private Toast backtoast;

Następnie,

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

To zadzwoni, finish()jeśli naciśniesz wstecz, gdy toast jest nadal widoczny, i tylko wtedy, gdy naciśnięcie wstecz spowoduje zamknięcie aplikacji.


zamiast this.finish()dzwonić, NavUtils.navigateUpFromSameTask(this);aby wrócić do poprzedniego ekranu / aktywności
Do Kra

Alternatywna odpowiedź do rozważenia tutaj . Nie zdecydowałem jeszcze, które podejście preferuję. Niektóre szczegóły połączonej odpowiedzi można dodać do tej odpowiedzi, w szczególności logikę anulowania toastu, gdy tylko użytkownik wyjdzie.
ToolmakerSteve,

14

Stosuję to znacznie prostsze podejście ...

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

Coś dziwnego dzieje się na tablecie Samsung Note. Musisz kilkakrotnie uderzyć szybko. Nie podoba mu się też podejście „backToast” ...
SoloPilot,

Czy działa lepiej w Note, jeśli anulujesz toast przed wyjściem? Zobacz to
ToolmakerSteve,

2

Zarówno twoja droga, jak i droga @ Steve'a są akceptowalnymi sposobami zapobiegania przypadkowym wyjściom.

Jeśli zdecydujesz się kontynuować implementację, będziesz musiał upewnić się, że backpress został zainicjowany na 0 i prawdopodobnie zaimplementuj Timerjakiś rodzaj, aby zresetować go z powrotem do 0 po naciśnięciu klawisza, po upływie czasu odnowienia. (~ 5 sekund wydaje się właściwe)


2

Może być również konieczne zresetowanie licznika, onPauseaby zapobiec przypadkom, gdy użytkownik naciska na stronę główną lub opuszcza go w inny sposób po pierwszym naciśnięciu wstecz. W przeciwnym razie nie widzę problemu.


1

Jeśli chcesz zamknąć aplikację z bezpośredniego działania drugiego bez przechodzenia do pierwszego działania, wypróbuj ten kod…

W drugiej czynności umieść ten kod.

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

I Twoja pierwsza czynność Umieść ten kod .....

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

Jest to najlepszy sposób, ponieważ jeśli użytkownik nie cofnie się o więcej niż dwie sekundy, zresetuje cofniętą wartość.

zadeklaruj jedną zmienną globalną.

 private boolean backPressToExit = false;

Zastąp onBackPressedmetodę.

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

zadeklaruj jedną zmienną, taką jak prywatna wartość logiczna backPressToExit = false
Yogesh Rathi

1) Zmień swoją odpowiedź tak, aby zawierała wspomniane wartości logiczne, zamiast mówić to w komentarzu. Aby ludzie mogli zobaczyć, gdzie powinna znajdować się deklaracja. 2) Rzeczywiście, jest to alternatywny sposób bycia świadomym czasu. Proszę wyjaśnić, dlaczego uważasz to za „najlepsze”. W szczególności wiąże się to z narzutem związanym z utworzeniem programu obsługi - co można dzięki temu zyskać?
ToolmakerSteve,

0

dodatkowo, przed wywołaniem musisz zamknąć okno dialogowe activity.super.onBackPressed(), w przeciwnym razie pojawi się błąd „Wyciek aktywności ...”.

Przykład w moim przypadku z biblioteką 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

użyj do .onBackPressed () z powrotem Określ działanie

@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
Wyjaśnij, co dodałeś do oryginalnego kodu i dlaczego.
ToolmakerSteve

0

Właśnie miałem ten problem i rozwiązałem go, dodając następującą metodę:

@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

Możesz również użyć onBackPressed, korzystając z dostosowanego Toast:

wprowadź opis obrazu tutaj

custom_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

Użyj tego, może pomóc.

@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();
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.