Mengklik tombol kembali dua kali untuk keluar dari suatu kegiatan

331

Saya perhatikan pola ini di banyak aplikasi dan game Android baru-baru ini: ketika mengklik tombol kembali untuk "keluar" dari aplikasi, Toastmuncul dengan pesan yang mirip dengan "Silakan klik KEMBALI lagi untuk keluar".

Saya bertanya-tanya, seperti yang sering saya lihat, apakah itu fitur bawaan yang entah bagaimana dapat Anda akses dalam suatu kegiatan? Saya telah melihat kode sumber dari banyak kelas tetapi sepertinya saya tidak dapat menemukan apa pun tentang itu.

Tentu saja, saya dapat memikirkan beberapa cara untuk mencapai fungsi yang sama dengan cukup mudah (yang paling mudah adalah dengan menyimpan boolean dalam aktivitas yang menunjukkan apakah pengguna sudah mengklik sekali ...) tapi saya bertanya-tanya apakah ada sesuatu yang sudah ada di sini .

EDIT : Seperti @LAS_VEGAS sebutkan, saya tidak benar-benar bermaksud "keluar" dalam arti tradisional. (mis. diakhiri) Maksud saya "kembali ke apa pun yang terbuka sebelum aktivitas awal aplikasi diluncurkan", jika itu masuk akal :)

Guillaume
sumber
[Android - Konfirmasi keluar aplikasi dengan bersulang] [1]: stackoverflow.com/questions/14006461/…
resource8218
1
Saya memiliki masalah yang sama ketika menggunakan Perpustakaan HoloEverywhere, terlalu sederhana Anda dapat menambahkan android: launchMode = "singleTask" kepada Anda definisi aktivitas dalam file manifes.
Sohayb Hassoun

Jawaban:

949

Dalam Aktivitas Jawa:

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

Dalam Kegiatan Kotlin:

private var doubleBackToExitPressedOnce = false
override fun onBackPressed() {
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed()
            return
        }

        this.doubleBackToExitPressedOnce = true
        Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show()

        Handler().postDelayed(Runnable { doubleBackToExitPressedOnce = false }, 2000)
    }

Saya pikir penangan ini membantu mengatur ulang variabel setelah 2 detik.

Sudheesh B Nair
sumber
43
Jawaban Terbaik! Anda juga dapat menambahkan kondisi jika (doubleBackToExitPressedOnce || fragmentManager.getBackStackEntryCount ()! = 0) {dalam kasus add berbasis fragmen
Anton Derevyanko
2
Saya setuju, ini jelas merupakan jawaban terbaik dan harus menjadi jawaban yang diterima.
BruceHill
3
Anda harus menghapus Runnable saat keluar dari aplikasi.
Wayne
Periksa jawaban saya. Saya telah mengubah jawaban yang diberikan oleh Sudheesh B Nairuntuk mencakup komentar yang disarankan di atas.
Mehul Joisar
18
Ini solusi / jawaban cepat yang bagus tapi saya tidak setuju itu solusi terbaik . Dan bagi mereka yang berpikir ini akan menjadi jawaban terbaik lagi saya tidak setuju. Solusi ini menyebabkan kebocoran dan akan membutuhkan upaya ekstra untuk penanganannya. Periksa aswers di bawah ini untuk perincian lebih lanjut.
Saro Taşciyan
226

Sudheesh B Nair memiliki jawaban yang bagus (dan dapat diterima) pada pertanyaan, yang menurut saya harus memiliki alternatif yang lebih baik seperti;

Apa yang salah dengan mengukur waktu berlalu dan memeriksa apakah TIME_INTERVALmilidetik (katakanlah 2000) berlalu sejak pers terakhir terakhir. Kode contoh berikut digunakan System.currentTimeMillis();untuk menyimpan waktu onBackPressed()disebut;

private static final int TIME_INTERVAL = 2000; // # milliseconds, desired time passed between two back presses.
private long mBackPressed;

@Override
public void onBackPressed()
{
    if (mBackPressed + TIME_INTERVAL > System.currentTimeMillis()) 
    { 
        super.onBackPressed(); 
        return;
    }
    else { Toast.makeText(getBaseContext(), "Tap back button in order to exit", Toast.LENGTH_SHORT).show(); }

    mBackPressed = System.currentTimeMillis();
}

Kembali pada kritik jawaban yang diterima ; Menggunakan flaguntuk menunjukkan jika ditekan di terakhir TIME_INTERVAL(mengatakan 2000) milidetik dan set - ulang adalah melalui Handler's postDelayed()metode adalah hal pertama yang datang dalam pikiran saya. Tetapi postDelayed()tindakan harus dibatalkan ketika aktivitas ditutup, menghapus Runnable.

Untuk menghapusnya Runnable, itu tidak boleh dinyatakan anonim , dan dinyatakan sebagai anggota bersama dengan Handleraswell. KemudianremoveCallbacks() metode Handlerdapat disebut dengan tepat.

Contoh berikut adalah demonstrasi;

private boolean doubleBackToExitPressedOnce;
private Handler mHandler = new Handler();

private final Runnable mRunnable = new Runnable() {
    @Override
    public void run() {
        doubleBackToExitPressedOnce = false;                       
    }
};

@Override 
protected void onDestroy() 
{ 
    super.onDestroy();

    if (mHandler != null) { mHandler.removeCallbacks(mRunnable); }
}

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

    mHandler.postDelayed(mRunnable, 2000);
}

Terima kasih kepada @NSouth karena berkontribusi; Untuk mencegah pesan roti muncul bahkan setelah aplikasi ditutup, Toastdapat dinyatakan sebagai anggota - katakan mExitToast- dan dapat dibatalkan via mExitToast.cancel();sebelum super.onBackPressed();panggilan.

Saro Taşciyan
sumber
9
Bagi mereka yang berpikir bahwa itu sama dengan yang dikatakan Sudheesh B Nair: Fungsionalitas yang sama, kinerja yang lebih baik. jadi +1.
BedirYilmaz
4
Saya suka jawaban ini dan saya pikir itu yang terbaik. Maksud saya, saya tidak berpikir itu, itu jawaban terbaik, untuk alasan yang disebutkan di atas. Saya harap Anda mendapatkan lebih banyak suara untuk yang ini. Satu komentar: tidak ada yang merasa aneh bahwa roti bakar bertahan beberapa detik setelah aplikasi ditutup? Tidak ada yang peduli untuk membatalkan bersulang? Saya tahu itu mungkin detail kecil tapi saya pikir itu harus terjadi. apa yang kalian pikirkan?
acrespo
1
@ joonty terima kasih sudah mengedit, kata kunci int itu telah hilang selama beberapa waktu. Ini akan dikompilasi sekarang (:
Saro Taşciyan
2
@NSouth Blok kode kedua adalah sampel menggunakan mHandlers untuk menunjukkannya membutuhkan lebih banyak usaha. Saya sarankan Anda mempertimbangkan untuk menggunakan blok kode pertama, yang tidak menggunakan penangan.
Saro Taşciyan
1
@ acrespo Saya kira kita memiliki solusi yang solid untuk pesan roti panggang bertahan setelah aplikasi ditutup sekarang.
Saro Taşciyan
30

Hanya berpikir saya akan membagikan bagaimana saya melakukannya pada akhirnya, saya hanya menambahkan dalam aktivitas saya:

private boolean doubleBackToExitPressedOnce = false;

@Override
protected void onResume() {
    super.onResume();
    // .... other stuff in my onResume ....
    this.doubleBackToExitPressedOnce = false;
}

@Override
public void onBackPressed() {
    if (doubleBackToExitPressedOnce) {
        super.onBackPressed();
        return;
    }
    this.doubleBackToExitPressedOnce = true;
    Toast.makeText(this, R.string.exit_press_back_twice_message, Toast.LENGTH_SHORT).show();
}

Dan itu berfungsi persis seperti yang saya inginkan. Termasuk pengaturan ulang keadaan kapan pun aktivitas dilanjutkan.

Guillaume
sumber
15
Dengan solusi ini, kedua mesin cetak belakang dapat memiliki jumlah waktu yang sewenang-wenang di antara mereka. Jadi Anda dapat menekan Backsekali dan kemudian tekan Backlagi satu menit kemudian dan aplikasi akan keluar. Ini bukan perilaku yang diharapkan pengguna.
BruceHill
1
Saya pikir ini masalah selera. Dalam hal ini, Anda hanya memberi tahu pengguna sekali saja, sehingga pengguna tahu ia ada dalam aktivitas utama dan tekan kembali yang lain akan keluar dari aplikasi (mungkin setelah pengguna menekan beberapa kali untuk kembali ke layar utama). Jika, kemudian, pengguna menekan kembali, kita bisa mengira dia ingin keluar dari aplikasi (kecuali dia telah menavigasi ke aktivitas lain dan mungkin lupa seberapa dalam dia mendapatkan). Di jawaban yang diterima di atas, Anda menganggap bahwa pengguna mungkin lupa bahwa dia sudah ada di layar utama. Keduanya baik-baik saja, tergantung pada apa yang Anda inginkan atau pertimbangkan.
Ferran Maylinch
4
@ Ferranaylinch - Saya tidak setuju. Ini bukan hanya masalah selera. Jika waktu yang signifikan telah berlalu, kita harus mengasumsikan bahwa pengguna telah melakukan tindakan lain sementara itu, dan tidak lagi mempertimbangkan apa yang dia lakukan sebelumnya dan memilih untuk tidak melanjutkan untuk menerapkan. Memang, semua kecuali pengguna yang paling luar biasa bahkan tidak akan tetap memilikinya dalam pikirannya bahwa dia sebelumnya melakukan itu. Tanpa batas waktu, Anda telah meninggalkan aplikasi dalam mode tak terlihat yang tidak bisa diketahui pengguna. Saya benar-benar menganggap itu sebagai desain antarmuka pengguna yang buruk. Pengguna akan terkejut.
ToolmakerSteve
IMHO, varian yang lebih baik di sini dan di sini .
ToolmakerSteve
26

Diagram Alir Proses: Tekan lagi untuk keluar.

Kode Java:

private long lastPressedTime;
private static final int PERIOD = 2000;

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
        switch (event.getAction()) {
        case KeyEvent.ACTION_DOWN:
            if (event.getDownTime() - lastPressedTime < PERIOD) {
                finish();
            } else {
                Toast.makeText(getApplicationContext(), "Press again to exit.",
                        Toast.LENGTH_SHORT).show();
                lastPressedTime = event.getEventTime();
            }
            return true;
        }
    }
    return false;
}
vBagaimana
sumber
1
Saya awalnya memilih ini sebagai membantu. Masalahnya adalah, untuk beberapa alasan, ini tidak berfungsi pada beberapa handset. Metode onBackPressed berfungsi paling baik, tetapi Anda tidak memiliki stempel waktu, sehingga Anda memerlukan penangan sesuai status jawaban yang diterima.
ravemir
23

Ada cara yang paling sederhana di antara semua jawaban ini.

Cukup tulis kode berikut di dalam onBackPressed()metode.

long back_pressed;

@Override
public void onBackPressed() {
    if (back_pressed + 1000 > System.currentTimeMillis()){
        super.onBackPressed();
    }
    else{
        Toast.makeText(getBaseContext(),
                "Press once again to exit!", Toast.LENGTH_SHORT)
                .show();
    }
    back_pressed = System.currentTimeMillis();
}

Anda perlu mendefinisikan back_pressedobjek seperti longdalam aktivitas.

Chintan Rathod
sumber
16

Solusi saya menggunakan snackbar:

Snackbar mSnackbar;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final LinearLayout layout = findViewById(R.id.layout_main);
    mSnackbar = Snackbar.make(layout, R.string.press_back_again, Snackbar.LENGTH_SHORT);
}

@Override
public void onBackPressed() {
    if (mSnackbar.isShown()) {
        super.onBackPressed();
    } else {
        mSnackbar.show();
    }
}

Sederhana dan bergaya.

Hugo Passos
sumber
2
Terima kasih atas solusi ini. Sederhana, efektif, tanpa risiko.
ping li
2
Solusi keluar dari kotak. (tepuk tangan)
Hitesh Dhamshaniya
13

Berdasarkan jawaban dan saran yang benar dalam komentar, saya telah membuat demo yang berfungsi dengan sangat baik dan menghapus panggilan balik handler setelah digunakan.

MainActivity.java

package com.mehuljoisar.d_pressbacktwicetoexit;

import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.widget.Toast;

public class MainActivity extends Activity {

    private static final long delay = 2000L;
    private boolean mRecentlyBackPressed = false;
    private Handler mExitHandler = new Handler();
    private Runnable mExitRunnable = new Runnable() {

        @Override
        public void run() {
            mRecentlyBackPressed=false;   
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public void onBackPressed() {

        //You may also add condition if (doubleBackToExitPressedOnce || fragmentManager.getBackStackEntryCount() != 0) // in case of Fragment-based add
        if (mRecentlyBackPressed) {
            mExitHandler.removeCallbacks(mExitRunnable);
            mExitHandler = null;
            super.onBackPressed();
        }
        else
        {
            mRecentlyBackPressed = true;
            Toast.makeText(this, "press again to exit", Toast.LENGTH_SHORT).show();
            mExitHandler.postDelayed(mExitRunnable, delay);
        }
    }

}

Saya harap ini akan membantu !!

Mehul Joisar
sumber
Apakah Anda yakin menghapus penangan dalam onBackPressed()memperbaiki masalah kebocoran memori ?
Saro Taşciyan
@ Zefnus: Ini akan memperbaiki sejauh yang saya tahu. Koreksi saya jika saya salah. Bagaimana Anda melacak masalah memori dengan kode di atas?
Mehul Joisar
11
 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);

Deklarasikan Variabelprivate boolean doubleBackToExitPressedOnce = false;

Tempel ini di Aktivitas Utama Anda dan ini akan menyelesaikan masalah Anda

Rakshith
sumber
10

Ini bukan ide yang baik untuk menggunakan Runnable ketika keluar dari aplikasi, saya baru-baru ini mencari cara yang lebih sederhana untuk merekam dan membandingkan periode antara dua klik tombol KEMBALI. Contoh kode sebagai berikut:

private static long back_pressed_time;
private static long PERIOD = 2000;

@Override
public void onBackPressed()
{
        if (back_pressed_time + PERIOD > System.currentTimeMillis()) super.onBackPressed();
        else Toast.makeText(getBaseContext(), "Press once again to exit!", Toast.LENGTH_SHORT).show();
        back_pressed_time = System.currentTimeMillis();
}

Ini akan melakukan trik untuk keluar dari aplikasi dengan mengklik dua kali tombol KEMBALI dalam periode penundaan tertentu yaitu 2000 milidetik dalam sampel.

Max Lee
sumber
8

Jawaban yang diterima adalah yang Terbaik tetapi jika Anda menggunakan Android Design Support Librarymaka Anda dapat menggunakan SnackBaruntuk Tampilan yang Lebih Baik.

   boolean doubleBackToExitPressedOnce = false;

    @Override
    public void onBackPressed() {
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed();
            return;
        }

        this.doubleBackToExitPressedOnce = true;

        Snackbar.make(findViewById(R.id.photo_album_parent_view), "Please click BACK again to exit", Snackbar.LENGTH_SHORT).show();

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

            @Override
            public void run() {
                doubleBackToExitPressedOnce=false;
            }
        }, 2000);
    }
Pratik Butani
sumber
7

Ini bukan fungsi bawaan. Saya pikir itu bahkan bukan perilaku yang direkomendasikan. Aplikasi Android tidak dimaksudkan untuk keluar:

Mengapa aplikasi Android tidak menyediakan opsi "Keluar"?

Caner
sumber
Poin yang diambil. Dengan keluar, maksud saya "kembali ke layar beranda"
Guillaume
3
Tetap saja ini bukan fungsionalitas bawaan. Namun saya tidak mengetahui adanya pedoman terhadap hal ini. Sebagai pengguna android, saya suka fungsi seperti itu.
Caner
6
  1. Deklarasikan variabel Toast global untuk MainActivity Class. contoh: Toast exitToast;
  2. Inisialisasi dalam metode tampilan onCreate. contoh: exitToast = Toast.makeText (getApplicationContext (), "Tekan kembali lagi untuk keluar", Toast.LENGTH_SHORT);
  3. Akhirnya buat onBackPressedMethod sebagai Follows:

    @Override
    public void onBackPressed() {
    
        if (exitToast.getView().isShown()) {
            exitToast.cancel();
            finish();
        } else {
            exitToast.show();
        }
    }

Ini berfungsi dengan benar, saya telah menguji. dan saya pikir ini jauh lebih sederhana.

Supto
sumber
5

Jawaban Zefnus menggunakan System.currentTimeMillis () adalah yang terbaik (+1). Cara saya melakukannya bukan lebih baik dari itu, tetapi masih mempostingnya untuk menambah ide-ide di atas.

Jika roti panggang tidak terlihat ketika tombol kembali ditekan, roti panggang ditampilkan, sedangkan, jika roti itu terlihat (punggung sudah ditekan sekali dalam Toast.LENGTH_SHORTwaktu terakhir ), maka roti itu keluar.

exitToast = Toast.makeText(this, "Press again to exit", Toast.LENGTH_SHORT);
.
.
@Override
public void onBackPressed() {
   if (exitToast.getView().getWindowToken() == null) //if toast is currently not visible
      exitToast.show();  //then show toast saying 'press againt to exit'
   else {                                            //if toast is visible then
      finish();                                      //or super.onBackPressed();
      exitToast.cancel();
   }
}
Kartik
sumber
1
Adalah cara yang baik untuk melakukan ini, tetapi jika Anda memiliki lebih banyak pesan bersulang tidak.
Boldijar Paul
@BoldijarPaul Tidak, kode ini hanya memeriksa status roti panggang tertentu. Jadi bersulang lain tidak akan mempengaruhi perilaku.
urgentx
5

Baru-baru ini, saya perlu menerapkan fitur tombol kembali ini di aplikasi saya. Jawaban atas pertanyaan awal itu berguna, tetapi saya harus mempertimbangkan dua hal lagi:

  1. Pada titik waktu tertentu, tombol kembali dinonaktifkan
  2. Aktivitas utama menggunakan fragmen dalam kombinasi dengan tumpukan belakang

Berdasarkan jawaban dan komentar, saya membuat kode berikut:

private static final long BACK_PRESS_DELAY = 1000;

private boolean mBackPressCancelled = false;
private long mBackPressTimestamp;
private Toast mBackPressToast;

@Override
public void onBackPressed() {
    // Do nothing if the back button is disabled.
    if (!mBackPressCancelled) {
        // Pop fragment if the back stack is not empty.
        if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
            super.onBackPressed();
        } else {
            if (mBackPressToast != null) {
                mBackPressToast.cancel();
            }

            long currentTimestamp = System.currentTimeMillis();

            if (currentTimestamp < mBackPressTimestamp + BACK_PRESS_DELAY) {
                super.onBackPressed();
            } else {
                mBackPressTimestamp = currentTimestamp;

                mBackPressToast = Toast.makeText(this, getString(R.string.warning_exit), Toast.LENGTH_SHORT);
                mBackPressToast.show();
            }
        }
    }
}

Kode di atas mengasumsikan bahwa perpustakaan dukungan digunakan. Jika Anda menggunakan fragmen tetapi bukan pustaka dukungan, Anda ingin menggantinya getSupportFragmentManager()dengangetFragmentManager() .

Hapus yang pertama if, jika tombol kembali tidak pernah dibatalkan. Hapus yang keduaif , jika Anda tidak menggunakan fragmen atau tumpukan kembali fragmen

Juga, penting untuk menyadari bahwa metode onBackPressedini didukung sejak Android 2.0. Periksa halaman ini untuk deskripsi yang lebih terperinci. Agar fitur back press berfungsi pada versi yang lebih lama, tambahkan metode berikut ke aktivitas Anda:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event)  {
    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ECLAIR
            && keyCode == KeyEvent.KEYCODE_BACK
            && event.getRepeatCount() == 0) {
        // Take care of calling this method on earlier versions of
        // the platform where it doesn't exist.
        onBackPressed();
    }

    return super.onKeyDown(keyCode, event);
}
Tomasz Nguyen
sumber
5

Di jawa

private Boolean exit = false; 

if (exit) {
onBackPressed(); 
}

 @Override
public void onBackPressed() {
    if (exit) {
        finish(); // finish activity
    } else {
        Toast.makeText(this, "Press Back again to Exit.",
                Toast.LENGTH_SHORT).show();
        exit = true;
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                exit = false;
            }
        }, 3 * 1000);

    }
}

Di kotlin

 private var exit = false

 if (exit) {
        onBackPressed()
         }

 override fun onBackPressed(){
           if (exit){
               finish() // finish activity
           }else{
            Toast.makeText(this, "Press Back again to Exit.",
                    Toast.LENGTH_SHORT).show()
            exit = true
            Handler().postDelayed({ exit = false }, 3 * 1000)

        }
    }
Praveen
sumber
4

Saya tahu ini adalah pertanyaan yang sangat lama, tetapi ini adalah cara termudah untuk melakukan apa yang Anda inginkan.

@Override
public void onBackPressed() {
   ++k; //initialise k when you first start your activity.
   if(k==1){
      //do whatever you want to do on first click for example:
      Toast.makeText(this, "Press back one more time to exit", Toast.LENGTH_LONG).show();
   }else{
      //do whatever you want to do on the click after the first for example:
      finish(); 
   }
}

Saya tahu ini bukan metode terbaik, tetapi berfungsi dengan baik!

Chris Rohit Brendan
sumber
3
Ini bukan perilaku umum "mengklik tombol kembali dua kali untuk keluar". Seperti yang ditunjukkan oleh komentar BruceHill tentang jawaban yang diterima, jawaban Anda tidak menangani masalah waktu juga
inankupeli
tetapi dengan ini Anda dapat mengklik kembali, itu akan menampilkan pesan, dan kemudian Anda bisa menunggu sedikit lebih lama, kembali lagi dan itu akan menutup aplikasi, dan itu tidak akan menangani perilaku waktu kembali ganda
Gastón Saillén
3

Untuk tujuan ini saya telah menerapkan fungsi berikut:

private long onRecentBackPressedTime;
@Override
public void onBackPressed() {
    if (System.currentTimeMillis() - onRecentBackPressedTime > 2000) {
       onRecentBackPressedTime = System.currentTimeMillis();
       Toast.makeText(this, "Please press BACK again to exit", Toast.LENGTH_SHORT).show();
       return;
     }
   super.onBackPressed();
}
Tetapi saya
sumber
3

Ini juga membantu ketika Anda memiliki aktivitas stack sebelumnya disimpan dalam stack.

Saya telah mengubah jawaban Sudheesh

boolean doubleBackToExitPressedOnce = false;

@Override
public void onBackPressed() {
    if (doubleBackToExitPressedOnce) {
        //super.onBackPressed();

  Intent intent = new Intent(Intent.ACTION_MAIN);
                    intent.addCategory(Intent.CATEGORY_HOME);
                    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);//***Change Here***
                    startActivity(intent);
                    finish();
                    System.exit(0);
        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);
} 
Arpit Patel
sumber
2
@Override public void onBackPressed() {
   Log.d("CDA", "onBackPressed Called");
   Intent intent = new Intent();
   intent.setAction(Intent.ACTION_MAIN);
   intent.addCategory(Intent.CATEGORY_HOME);

   startActivity(intent);
}
Sai Aditya
sumber
1
Bagaimana ini bahkan menangani skenario pers ganda? Segera setelah saya membalas, ini meluncurkan aktivitas.
kilokahn
2

Metode yang sedikit lebih baik daripada Zefnus . Panggil System.currentTimeMillis () hanya satu kali dan hilangkan return;:

long previousTime;

@Override
public void onBackPressed()
{
    if (2000 + previousTime > (previousTime = System.currentTimeMillis())) 
    { 
        super.onBackPressed();
    } else {
        Toast.makeText(getBaseContext(), "Tap back button in order to exit", Toast.LENGTH_SHORT).show();
    }
}
k8C
sumber
2

Ini adalah kode kerja lengkap. Dan juga jangan lupa untuk menghapus callback sehingga tidak menyebabkan kebocoran memori di aplikasi. :)

private boolean backPressedOnce = false;
private Handler statusUpdateHandler;
private Runnable statusUpdateRunnable;

public void onBackPressed() {
        if (backPressedOnce) {
            finish();
        }

        backPressedOnce = true;
        final Toast toast = Toast.makeText(this, "Press again to exit", Toast.LENGTH_SHORT);
        toast.show();

        statusUpdateRunnable = new Runnable() {
            @Override
            public void run() {
                backPressedOnce = false;
                toast.cancel();  //Removes the toast after the exit.
            }
        };

        statusUpdateHandler.postDelayed(statusUpdateRunnable, 2000);
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if (statusUpdateHandler != null) {
        statusUpdateHandler.removeCallbacks(statusUpdateRunnable);
    }
}
Saket Kumar
sumber
2

Di sini, saya telah menggeneralisasi menulis kode untuk jumlah N tap. Kode ini juga ditulis untuk opsi Aktifkan Pengembang di ponsel perangkat android. Bahkan Anda dapat menggunakan ini untuk mengaktifkan fitur saat pengembang menguji aplikasi.

 private Handler tapHandler;
 private Runnable tapRunnable;
 private int mTapCount = 0;
 private int milSecDealy = 2000;

onCreate(){
 ...
tapHandler = new Handler(Looper.getMainLooper());

 }

Panggil askToExit () pada opsi backpress atau logout.

private void askToExit() {
   if (mTapCount >= 2) {
    releaseTapValues();
    /* ========= Exit = TRUE  =========  */
   }

   mTapCount++;
   validateTapCount();
  }


  /* Check with null to avoid create multiple instances of the runnable */
  private void validateTapCount() {
   if (tapRunnable == null) {
    tapRunnable = new Runnable() {
     @Override
     public void run() {
      releaseTapValues();
      /* ========= Exit = FALSE  =========  */
     }
    };
    tapHandler.postDelayed(tapRunnable, milSecDealy);
   }
  }

  private void releaseTapValues() {
   /* Relase the value  */
   if (tapHandler != null) {
    tapHandler.removeCallbacks(tapRunnable);
    tapRunnable = null; /* release the object */
    mTapCount = 0; /* release the value */
   }
  }


  @Override
  protected void onDestroy() {
   super.onDestroy();
   releaseTapValues();
  }
Chintan Khetiya
sumber
2

Saya menggunakan ini

import android.app.Activity;
import android.support.annotation.StringRes;
import android.widget.Toast;

public class ExitApp {

    private static long lastClickTime;

    public static void now(Activity ctx, @StringRes int message) {
        now(ctx, ctx.getString(message), 2500);
    }

    public static void now(Activity ctx, @StringRes int message, long time) {
        now(ctx, ctx.getString(message), time);
    }

    public static void now(Activity ctx, String message, long time) {
        if (ctx != null && !message.isEmpty() && time != 0) {
            if (lastClickTime + time > System.currentTimeMillis()) {
                ctx.finish();
            } else {
                Toast.makeText(ctx, message, Toast.LENGTH_SHORT).show();
                lastClickTime = System.currentTimeMillis();
            }
        }
    }

}

gunakan untuk dalam acaraonBackPressed

@Override
public void onBackPressed() {
   ExitApp.now(this,"Press again for close");
}

atau ExitApp.now(this,R.string.double_back_pressed)

untuk mengubah detik, perlu untuk milidetik yang tertutup dan ditentukan

ExitApp.now(this,R.string.double_back_pressed,5000)

Server web
sumber
2

Ketika HomeActivity berisi laci navigasi dan fungsi ganda ditekan () untuk keluar dari aplikasi. (Jangan lupa menginisiasi variabel global boolean doubleBackToExitPressedOnce = false;) penangan baru setelah 2 detik mengatur variabel doubleBackPressedOnce menjadi false

@Override
public void onBackPressed() {
    DrawerLayout drawer = findViewById(R.id.drawer_layout);
    if (drawer.isDrawerOpen(GravityCompat.END)) {
        drawer.closeDrawer(GravityCompat.END);
    } else {
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed();
            moveTaskToBack(true);
            return;
        } else {
            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);
        }
    }
}
Abhishek S
sumber
1
boolean doubleBackToExitPressedOnce = false;

@Override
public void onBackPressed() {
    if (doubleBackToExitPressedOnce) {
        super.onBackPressed();
        return;
    }

    this.doubleBackToExitPressedOnce = true;

    Snackbar.make(findViewById(R.id.photo_album_parent_view), "Please click BACK again to exit", Snackbar.LENGTH_SHORT).show();

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

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

Beberapa Perbaikan dalam jawaban Sudheesh B Nair, saya perhatikan itu akan menunggu penangan bahkan sambil menekan kembali dua kali segera, jadi batalkan penangan seperti yang ditunjukkan di bawah ini. Saya telah membatalkan toast untuk mencegahnya muncul setelah aplikasi keluar.

 boolean doubleBackToExitPressedOnce = false;
        Handler myHandler;
        Runnable myRunnable;
        Toast myToast;

    @Override
        public void onBackPressed() {
            if (doubleBackToExitPressedOnce) {
                myHandler.removeCallbacks(myRunnable);
                myToast.cancel();
                super.onBackPressed();
                return;
            }

            this.doubleBackToExitPressedOnce = true;
            myToast = Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT);
            myToast.show();

            myHandler = new Handler();

            myRunnable = new Runnable() {

                @Override
                public void run() {
                    doubleBackToExitPressedOnce = false;
                }
            };
            myHandler.postDelayed(myRunnable, 2000);
        }
Divyang Panchal
sumber
1

Ini sama dengan respons yang diterima dan paling banyak dipilih tetapi ini menggunakan Snackbar bukan Toast.

boolean doubleBackToExitPressedOnce = false;

    @Override
    public void onBackPressed() {
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed();
            return;
        }

        this.doubleBackToExitPressedOnce = true;
        Snackbar.make(content, "Please click BACK again to exit", Snackbar.LENGTH_SHORT)
                .setAction("Action", null).show();


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

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

Dalam kasus saya, saya bergantung pada yang Snackbar#isShown()lebih baik UX.

private Snackbar exitSnackBar;

@Override
public void onBackPressed() {
    if (isNavDrawerOpen()) {
        closeNavDrawer();
    } else if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
        if (exitSnackBar != null && exitSnackBar.isShown()) {
            super.onBackPressed();
        } else {
            exitSnackBar = Snackbar.make(
                    binding.getRoot(),
                    R.string.navigation_exit,
                    2000
            );
            exitSnackBar.show();
        }
    } else {
        super.onBackPressed();
    }
}
Kasim Rangwala
sumber
1

Untuk aktivitas yang memiliki Navigasi Laci , Gunakan kode berikut untuk OnBackPressed ()

boolean doubleBackToExitPressedOnce = false;

@Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            if (doubleBackToExitPressedOnce) {
                if (getFragmentManager().getBackStackEntryCount() ==0) {
                    finishAffinity();
                    System.exit(0);
                } else {
                    getFragmentManager().popBackStackImmediate();
                }
                return;
            }

            if (getFragmentManager().getBackStackEntryCount() ==0) {
                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);
            } else {
                getFragmentManager().popBackStackImmediate();
            }
        }
    }
Priya Rajan
sumber
1

Ini cara lain ... menggunakan metode CountDownTimer

private boolean exit = false;
@Override
public void onBackPressed() {
        if (exit) {
            finish();
        } else {
            Toast.makeText(this, "Press back again to exit",
                    Toast.LENGTH_SHORT).show();
            exit = true;
            new CountDownTimer(3000,1000) {

                @Override
                public void onTick(long l) {

                }

                @Override
                public void onFinish() {
                    exit = false;
                }
            }.start();
        }

    }
Anuj Sain
sumber