Bir etkinlikten çıkmak için geri düğmesine iki kez tıklanması


330

Son zamanlarda birçok Android uygulamasında ve oyununda bu kalıbı fark ettim: uygulamadan "çıkmak" için geri düğmesini tıkladığınızda, Toast için lütfen tekrar GERİ tıklayın" benzeri bir mesaj gelir.

Daha sık gördüğüm gibi, bir aktivitede bir şekilde erişebileceğiniz yerleşik bir özellik olduğunu merak ediyordum. Birçok sınıfın kaynak koduna baktım ama bununla ilgili bir şey bulamıyorum.

Tabii ki, aynı işlevselliği oldukça kolay bir şekilde elde etmenin birkaç yolunu düşünebilirim (en kolayı, kullanıcının zaten bir kez tıklayıp tıklamadığını gösteren aktivitede bir boole tutmaktır ...) Ama zaten burada bir şey olup olmadığını merak ediyordum .

EDIT : @LAS_VEGAS belirttiği gibi, gerçekten geleneksel anlamda "çıkış" demek istemiyordu. (yani sonlandırıldı) "Uygulama başlatma etkinliği başlatılmadan önce açık olan her şeye geri dönmek" anlamına geliyordu.


[Android - Uygulama çıkışını tost ile onaylayın] [1]: stackoverflow.com/questions/14006461/…
resource8218

1
HoloEverywhere Kütüphanesi kullanırken aynı sorunu vardı, çok basitçe manifest dosyasında aktivite tanımı size android ekleyebilirsiniz: launchMode = "singleTask".
Sohayb Hassoun


Yanıtlar:


947

Java Etkinliğinde:

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

Kotlin Etkinliğinde:

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

Bu işleyicinin 2 saniye sonra değişkeni sıfırlamaya yardımcı olduğunu düşünüyorum.


43
En iyi cevap! Ayrıca (doubleBackToExitPressedOnce || fragmentManager.getBackStackEntryCount ()! = 0) {Parça tabanlı ekleme durumunda
Anton Derevyanko

2
Katılıyorum, bu kesinlikle en iyi cevap ve kabul edilen cevap olmalı.
BruceHill

3
Uygulamadan çıkarken Runnable'ı kaldırmalısınız.
Wayne

Cevabımı kontrol et.Yukarıdaki Sudheesh B Nairönerilen yorumları kapsayacak şekilde verilen cevabı değiştirdim .
Mehul Joisar

18
Güzel ve hızlı bir çözüm / cevap ama bunun en iyi çözüm olduğu konusunda hemfikir değilim . Bunun en iyi cevap olacağını düşünenler için aynı fikirde değilim. Bu çözüm sızıntılara neden olur ve kullanım için ekstra çaba gerektirir. Daha fazla ayrıntı için aşağıdaki soruları kontrol edin .
Saro Taşciyan

226

Sudheesh B Nair'in güzel (ve kabul edilmiş) bir cevabı var, ki bence daha iyi bir alternatif olmalı;

Geçen zamanı ölçmek ve TIME_INTERVALmilisaniyelerin (diyelim 2000) son geri basıştan bu yana geçip geçmediğini kontrol etmek yanlış . Aşağıdaki örnek kod System.currentTimeMillis();zamanı saklamak için kullanılır onBackPressed();

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

Kabul edilen cevap eleştirisine geri dönelim ; Bir kullanarak flago sonuncu basıldığında ise belirtmek için TIME_INTERVAL(2000 say) milisaniye ve set - reset yoluyladır Handlerbireyin postDelayed()yöntem zihnimde gelen ilk şeydi. Ancak, postDelayed()etkinlik kapatıldığında eylem iptal edilerekRunnable .

Kaldırmak için anonimRunnable ilan edilmemeli ve aynı zamanda üye olarak ilan edilmemelidir . Sonra yöntemiHandlerremoveCallbacks()Handler uygun şekilde çağrılabilir.

Aşağıdaki örnek gösterimdir;

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

@NSouth'a katkılarından dolayı teşekkür ederiz; Tost mesajının uygulama kapatıldıktan sonra bile görünmesini önlemek Toastiçin üye olarak söylenebilir - diyelim ki mExitToast- çağrıdan mExitToast.cancel();hemen önce iptal edilebilir super.onBackPressed();.


9
Sudheesh B Nair'in söylediklerinin aynı olduğunu düşünenler için: Aynı işlevsellik, daha iyi performans. yani +1.
BedirYilmaz

4
Bu yanıtı beğendim ve bence en iyisi bu. Demek istediğim, yukarıda belirtilen nedenlerden dolayı, bunun en iyi cevap olduğunu düşünmüyorum. Umarım bunun için daha fazla oy alırsınız. Yine de bir yorum: kimse bunu kapattıktan sonra tost birkaç saniye devam etmesini tuhaf bulamıyor? Kimse tostu iptal etmeyi umursamıyor mu? Bunun küçük bir detay olabileceğini biliyorum ama bunun olması gerektiğini düşünüyorum. Siz ne düşünüyorsunuz?
acrespo

1
@joonty düzenleme için teşekkürler, int anahtar kelimesi bir süredir eksik. Şimdi derlenecek (:
Saro Taşciyan

2
@NSouth İkinci kod bloğu, daha fazla çaba gerektirdiğini göstermek için mHandlers kullanan bir örnektir. İşleyici kullanmayan ilk kod bloğunu kullanmayı düşünmenizi öneririm.
Saro Taşciyan

1
@acrespo Sanırım tost mesajı için uygulama kapatıldıktan sonra da devam eden sağlam bir çözümümüz var .
Saro Taşciyan

30

Sonunda nasıl yaptığımı paylaşacağımı düşündüm, sadece aktiviteme ekledim:

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

Ve tam istediğim gibi çalışıyor. Etkinlik her başlatıldığında durumun sıfırlanması dahil.


15
Bu çözüm ile iki arka baskı makinesi aralarında keyfi bir zamana sahip olabilir. Böylece bir Backkez basabilir ve Backbir dakika sonra tekrar basabilirsiniz , uygulama çıkacaktır. Bu kullanıcının bekleyeceği davranış değildir.
BruceHill

1
Bence bu bir zevk meselesi. Bu durumda kullanıcıyı yalnızca bir kez bilgilendirirsiniz, böylece kullanıcı ana etkinlikte olduğunu bilir ve başka bir geri basma uygulamadan çıkacaktır (muhtemelen ana ekrana geri dönmek için birkaç kez bastıktan sonra). Daha sonra, kullanıcı tekrar basarsa, uygulamadan çıkmak istediğini varsayabiliriz (başka bir etkinliğe gitmediği ve ne kadar derine indiğini izlemediği sürece). Yukarıdaki kabul edilen cevapta, kullanıcının zaten ana ekranda olduğunu unutabileceğini düşünürsünüz. Her ikisi de, ne istediğiniz veya düşündüğünüze bağlı olarak iyidir.
Ferran Maylinch

4
@FerranMaylinch - Katılmıyorum. Bu sadece bir zevk meselesi değil. Önemli zaman geçti, biz gereken kullanıcı bu arada diğer eylemleri yaptığını varsayalım ve artık daha önce yaptıklarını gördüğü ve devam etmek değil seçti uygulamak. Gerçekten de, en istisnai kullanıcı hariç, daha önce yaptığı şeyi aklından bile geçirmeyecektir. Zaman sınırı olmadan, uygulamayı kullanıcının bilmediği hiçbir şekilde görünmez bir modda bıraktınız . Kesinlikle kötü kullanıcı arayüzü tasarımı olduğunu düşünüyorum. Kullanıcılar şaşıracak.
ToolmakerSteve

IMHO, burada ve burada daha iyi varyantlar .
ToolmakerSteve

26

Proses Akış Şeması: Çıkmak için tekrar basın.

Java Kodu:

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

1
Ben initally yararlı olarak oy. Sorun, bazı nedenlerden dolayı, bu bazı el cihazlarında çalışmıyor. OnBackPressed yöntemi en iyi şekilde çalışır, ancak daha sonra zaman damgalarınız yoktur, bu nedenle kabul edilen yanıt durumları olarak işleyicilere ihtiyacınız vardır.
ravemir

23

Tüm bu cevaplar arasında en basit yol var.

Sadece aşağıdaki kodu onBackPressed()yönteme yazın.

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

back_pressedNesneyi longetkinlik olarak tanımlamanız gerekir .


16

Snackbar kullanarak çözümüm:

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

Basit ve şık.


2
Bu çözüm için teşekkürler. Basit, etkili, risk yok.
ping li

2
Kullanıma hazır çözüm. (clap)
Hitesh Dhamshaniya

13

Yorumlardaki doğru cevap ve önerilere dayanarak, kesinlikle iyi çalışan ve kullanıldıktan sonra işleyici geri aramalarını kaldıran bir demo oluşturdum.

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

}

Umarım faydalı olacaktır!


Belirli içinde Handler kaldırıyorsunuz onBackPressed()düzeltme bellek sızıntısı sorunu?
Saro Taşciyan

@Zefnus: Bildiğim kadarıyla düzelecek. Eğer Yanlışsam beni düzelt. Yukarıdaki kodla ilgili bellek sorununu nasıl izlediniz?
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);

Değişken Bildirprivate boolean doubleBackToExitPressedOnce = false;

Bunu Ana Etkinliğinize yapıştırın, bu sorununuzu çözecektir


10

Uygulamadan çıkarken bir Runnable kullanmak iyi bir fikir değil, son zamanlarda iki GERİ düğmesi tıklaması arasındaki süreyi kaydetmek ve karşılaştırmak için çok daha basit bir yol buluyorum. Örnek kod aşağıdaki gibi:

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

Bu, örnekte 2000 milisaniye olan belirli bir gecikme süresi içinde çift GERİ düğmesine tıklama ile uygulamadan çıkmak için hile yapar.


8

Kabul edilen cevap en iyisidir ancak kullanıyorsanız Android Design Support Librarydaha SnackBariyi görüntüleme için kullanabilirsiniz .

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

7

Yerleşik bir işlevsellik değildir. Bence önerilen davranış bu değil. Android uygulamalarının çıkması amaçlanmamıştır:

Android uygulamaları neden "Çıkış" seçeneği sunmuyor?


Alınan nokta. Çıkmakla, "ana ekrana geri dönmek" demek istedim
Guillaume

3
Yine de yerleşik bir işlevsellik değildir. Ancak buna karşı herhangi bir rehberden habersizim. Bir android kullanıcısı olarak, bu işlevselliği seviyorum.
Caner

6
  1. MainActivity Sınıfı için genel bir Tost değişkeni bildirin. örnek: Tost exitToast;
  2. OnCreate görünüm yönteminde başlatın. örnek: exitToast = Toast.makeText (getApplicationContext (), "Çıkmak için tekrar basın", Toast.LENGTH_SHORT);
  3. Son olarak aşağıdaki gibi bir onBackPressedMethod oluşturun:

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

Bu doğru çalışıyor, test ettim. ve bence bu çok daha basit.


5

Zefnus'un System.currentTimeMillis () kullanarak verdiği yanıt en iyisidir (+1). Yaptığım gibi değil daha iyi , ama yine de yukarıdaki fikirlere eklemek için gönderiyor.

Geri düğmesine basıldığında tost görünmüyorsa, tost görüntülenirken görünürse (son Toast.LENGTH_SHORTkez bir kez zaten basılmışsa ), o zaman çıkar.

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

1
Bunu yapmanın iyi bir yoludur, ancak daha fazla tost mesajınız yoksa değildir.
Boldijar Paul

@BoldijarPaul Hayır, bu kod yalnızca söz konusu tostun durumunu kontrol eder. Yani diğer tostlar davranışı etkilemez.
urgentx

5

Son zamanlarda, bu geri düğmesi özelliğini bir uygulamada uygulamam gerekiyordu. Orijinal sorunun cevabı faydalıydı, ancak iki noktayı daha dikkate almak zorunda kaldım:

  1. Zamanın bazı noktalarında geri düğmesi devre dışı bırakılır
  2. Ana faaliyet, parçaları bir yığın yığını ile birlikte kullanmaktır

Cevaplara ve yorumlara dayanarak aşağıdaki kodu oluşturdum:

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

Yukarıdaki kod, destek kitaplığının kullanıldığını varsayar. Eğer parçaları ancak destek kütüphane kullanırsanız, değiştirmek istiyor getSupportFragmentManager()tarafındangetFragmentManager() .

ifGeri düğmesi hiçbir zaman iptal edilmezse ilkini kaldırın . İkincisini kaldırifEğer parça veya parça arka yığını kullanmıyorsanız

Ayrıca, yöntemin onBackPressedAndroid 2.0'dan beri desteklendiğini bilmek önemlidir . Ayrıntılı bir açıklama için bu sayfayı kontrol edin . Geri basma özelliğinin eski sürümlerde de çalışmasını sağlamak için etkinliğinize aşağıdaki yöntemi ekleyin:

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

5

Java'da

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

    }
}

Kotlin'de

 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)

        }
    }

4

Bunun çok eski bir soru olduğunu biliyorum, ama istediğini yapmanın en kolay yolu bu.

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

Bunun en iyi yöntem olmadığını biliyorum, ama iyi çalışıyor!


3
Bu "çıkmak için iki kez geri tıklamak" genel davranışı değildir. BruceHill'in kabul edilen cevaplara yaptığı yorum gibi, cevabınız da zaman sorununu ele
almıyor

ancak bununla geri tıklayabilirsiniz, mesajı gösterecek ve sonra biraz daha bekleyebilir, tekrar geri dönebilir ve uygulamayı kapatacak ve çift geri zamanlama davranışını ele
almayacak

3

Bu amaçla aşağıdaki işlevi yerine getirdim:

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

3

Bu, daha önce yığınta saklanan yığın faaliyetiniz olduğunda da yardımcı olur.

Sudheesh'in cevabını değiştirdim

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

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

1
Bu, çift baskı senaryosunu nasıl ele alıyor? Geri adım attığımda, bu bir etkinlik başlattı.
kilokahn

2

Bence Zefnus'tan biraz daha iyi bir yöntem . System.currentTimeMillis () işlevini yalnızca bir kez arayın ve atlayın 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();
    }
}

2

İşte tam çalışma kodu. Ayrıca, uygulamada bellek sızıntısına neden olmaması için geri çağrıları kaldırmayı da unutmayın. :)

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

2

Burada, genel olarak N musluk sayıları için kod yazma var. Kod, android cihaz telefonunda Geliştirici Etkinleştir seçeneği için de benzer şekilde yazılmıştır. Geliştiriciyi uygulamayı test ederken özellikleri etkinleştirmek için bile bunu kullanabilirsiniz.

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

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

 }

Geri basma veya çıkış seçeneğinde askToExit () öğesini çağırın .

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

2

Bunu kullanıyorum

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

}

için kullanmak olay içindeonBackPressed

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

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

değişim saniye için yakın, belirtilen milisaniye ihtiyacı

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


2

HomeActivity, uygulamadan çıkmak için gezinme çekmecesi ve double backPressed () işlevini içerdiğinde. (Genel değişken boolean doubleBackToExitPressedOnce = false; initilize etmeyi unutmayın.) 2 saniye sonra yeni işleyici doubleBackPressedOnce değişkenini false olarak ayarlayın

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

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

1

Sudheesh B Nair'in cevabındaki bazı iyileştirmeler, hemen iki kez geri basarken bile işleyiciyi bekleyeceğini fark ettim, bu yüzden aşağıda gösterildiği gibi işleyiciyi iptal edin. Uygulamadan çıktıktan sonra görüntülenmesini önlemek için tost ekledim.

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

1

Bu, kabul edilen ve en çok oy verilen yanıtla aynıdır, ancak bu snip, Toast yerine Snackbar kullandı.

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

1

Benim durumumda, Snackbar#isShown()daha iyisine güveniyorum 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();
    }
}

1

Gezinme Çekmecesi olan etkinlik için OnBackPressed () için aşağıdaki kodu kullanın

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

1

İşte başka bir yol ... CountDownTimer yöntemini kullanarak

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

    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.