Android: maneira adequada de usar onBackPressed () com o Toast

85

Eu escrevi um trecho de código que fornecerá ao usuário um prompt pedindo que pressione a tecla Voltar novamente se quiser sair. Atualmente, tenho meu código funcionando até certo ponto, mas sei que está mal escrito e presumo que haja uma maneira melhor de fazê-lo. Quaisquer sugestões seriam úteis!

Código:

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

    if (backpress>1) {
        this.finish();
    }
}
usuario
fonte
5
Substitua this.finish()por super.onBackPressed();.
Fred de
5
em this.finish()vez de ligar NavUtils.navigateUpFromSameTask(this);para voltar à tela / atividade anterior
Para Kra

Respostas:

213

Gostaria de implementar uma caixa de diálogo perguntando ao usuário se ele deseja sair e, em seguida, chamar super.onBackPressed()se ele quiser.

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

No exemplo acima, você precisará substituir WelcomeActivity pelo nome de sua atividade.

Steve Prentice
fonte
isso funciona, mas no meu caso o popup é mostrado apenas por alguns milissegundos e depois desaparece e a nova janela é mostrada. Não tenho tempo de clicar em sim ou não, e se eu depurar, não passa para o método onClick. Por quê?
Accollativo
4
@Accollativo, parece que você ainda tem uma chamada para super.onBackPressed()na sua onBackPressed()definição (diferente daquela dentro do método onClick)?
Steve Prentice,
6
Cada aplicativo que vi favorece o método de "segundo pressionamento". Um usuário que acidentalmente aperta a tecla Voltar ficará irritado se uma caixa de diálogo for exibida. A torrada é menos intrusiva.
Karmic Coder
@Steve Prentice Eu uso esse trecho em meu aplicativo, mas e se tivermos um processo em execução enquanto estamos apoiando nossa atividade - o processo ainda está em execução. Como consertar isso? Se eu usar, android.os.Process.killProcess(android.os.Process.myPid());mas a animação entre as atividades não é tão suave. Em vez disso, ele exibe uma tela preta piscando por cerca de metade do segundo.
Stanimir Yakimov
1
@Stanimir Yakimov, dê uma olhada nos serviços do Android para executar processos em segundo plano. Isso tornará o gerenciamento do seu ciclo de vida mais fácil. Se você ainda não conseguiu descobrir, sugiro criar uma nova pergunta.
Steve Prentice
19

Você não precisa de um contador para prensas traseiras.

Basta armazenar uma referência à torrada que é mostrada:

private Toast backtoast;

Então,

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

Isso chamará finish()se você pressionar de volta enquanto a torrada ainda estiver visível e somente se pressionar de volta resultar na saída do aplicativo.

Siidheesh
fonte
em this.finish()vez de ligar NavUtils.navigateUpFromSameTask(this);para voltar à tela / atividade anterior
Para Kra
Uma resposta alternativa a considerar aqui . Ainda não decidi qual abordagem prefiro. Alguns detalhes da resposta vinculada podem ser adicionados a esta, especificamente a lógica para cancelar o brinde assim que o usuário sair.
Toolmaker Steve
14

Eu uso essa abordagem muito mais simples ...

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
        }
    }
}
SoloPilot
fonte
Algo estranho acontece em um tablet Samsung Note. Precisa bater de volta várias vezes rápido. Ele também não gosta da abordagem 'backToast' ...
SoloPilot
Funciona melhor no Note se você cancelar a torrada antes de sair? Veja isto
ToolmakerSteve
2

Tanto a sua maneira como a maneira de @Seus são formas aceitáveis ​​de prevenir saídas acidentais.

Se escolher continuar com sua implementação, você precisará certificar-se de que o backpress foi inicializado em 0 e, provavelmente, implementar um Timerde algum tipo para redefini-lo de volta a 0 ao pressionar a tecla, após um período de resfriamento. (Cerca de 5 segundos parece certo)

Sim
fonte
2

Você também pode precisar reiniciar o contador onPausepara evitar casos em que o usuário pressione home ou navegue por algum outro meio após o primeiro pressionamento de volta. Caso contrário, não vejo um problema.

Alex Gitelman
fonte
1

Se você deseja sair de seu aplicativo da segunda atividade direta sem ir para a primeira atividade, tente este código ...

Na segunda atividade coloque este código.

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

E sua primeira atividade coloque este código ...

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

}

Cã tabish
fonte
1

Esta é a melhor maneira, porque se o usuário não voltar mais de dois segundos, então redefina o valor comprimido de volta.

declara uma variável global.

 private boolean backPressToExit = false;

onBackPressedMétodo de substituição .

@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);
}
Yogesh Rathi
fonte
declara uma variável como booleano privado backPressToExit = false
Yogesh Rathi
1) Edite sua resposta para incluir o booleano que você mencionou, em vez de dizer isso em um comentário. Para que as pessoas possam ver onde deve estar a declaração. 2) Na verdade, esta é uma forma alternativa de estar ciente do tempo. Explique por que você considera isso "melhor". Especificamente, isso tem a sobrecarga de criar um manipulador - o que se ganha com isso?
Toolmaker Steve
0

além disso, você precisa dissmis dialog antes de chamar activity.super.onBackPressed(), caso contrário, você obterá o erro "Activity has leaked ..".

Exemplo no meu caso com a biblioteca 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();
    }
KaMChy
fonte
0

use para .onBackPressed () para voltar a especificar a atividade

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

    if (backpress>1) {
        this.finish();
    }
}
M.zar
fonte
1
Explique o que você adicionou ao código original e por quê.
Toolmaker Steve
0

Acabei de ter esse problema e resolvi-o adicionando o seguinte método:

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

Você também pode usar onBackPressed das seguintes maneiras usando o Toast personalizado:

insira a descrição da imagem aqui

personalizado_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);
}
Pankaj Lilan
fonte
0

Use isso, pode ajudar.

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