Geçmiş yığınının tamamını temizleyin ve Android'de yeni bir etkinlik başlatın


332

Tüm geçmişi ondan önce temizleyerek yığın üzerinde bir etkinlik başlatmak mümkün mü?

Durum

A-> B-> C veya B-> C'ye giden bir etkinlik yığını var (ekran A kullanıcı belirtecini seçer, ancak birçok kullanıcının yalnızca tek bir belirteci vardır).

Ekran C'de kullanıcı , ekran B'yi geçersiz kılan bir işlem yapabilir, bu nedenle uygulama, zaten yığında olup olmadığına bakılmaksızın A ekranına götürmek ister. Ekran A daha sonra uygulamamdaki yığın üzerindeki tek öğe olmalıdır.

notlar

Benzer başka sorular da var, ancak bu soruyu cevaplayan bir şey bulamadım. Aramaya çalıştım getParent().finish()- bu her zaman boş bir işaretçi istisnasıyla sonuçlanır. FLAG_ACTIVITY_CLEAR_TOPyalnızca etkinlik zaten yığıntaysa çalışır.

Yanıtlar:


658

API düzey 11'de yalnızca bunun için yeni bir Hedef Bayrağı eklendi: Hedef.FLAG_ACTIVITY_CLEAR_TASK

Sadece açıklığa kavuşturmak için şunu kullanın:

Java

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);


Kotlin

intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK


Ne yazık ki API lvl <= 10 için henüz buna temiz bir çözüm bulamadım. "DontHackAndroidLikeThis" çözüm aslında saf hackery olduğunu. Bunu yapmamalısın. :)

Düzenleme: @ Ben Pearson'ın yorumuna göre, API <= 10 için şimdi aynı intentCompat sınıfını kullanabilirsiniz . IntentCompat.FLAG_ACTIVITY_CLEAR_TASKGörevi temizlemek için bayrak kullanılabilir . Böylece API öncesi seviye 11'i de destekleyebilirsiniz.


23
Açıklığa kavuşturmak için şunu kullanın: intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
— Kullanıcı123321

2
Intent.FLAG_ACTIVITY_NEW_TASK olmadan uygulama bazen sadece android 4'te kendini kapatır
— max4ever

22
IntentCompat'ın görevi şimdi temizleyecek bir bayrağı da var, bu nedenle API öncesi düzey 11'i destekleyebilirsiniz - developer.android.com/reference/android/support/v4/content/…
— Ben Pearson

10
IntentCompat.FLAG_ACTIVITY_CLEAR_TASK, API düzeyi <10 olan cihazlarda yok sayılır. Developer.android.com/reference/android/support/v4/content/…
— David

7
IntentCompat'ın bayrağı sadece bir çarpışmayı önlemek içindir, ancak @David'in söylediği gibi bir şey yapmaz.
— Ağustos'ta Sloy

49

Durum 1: Sadece iki A ve B etkinliği:

Burada Aktivite akışı A-> B'dir. B'den geri düğmesine basıldığında, uygulamayı kapatmalı ve Aktivite B'yi sadece bir çağrı bitirmeden () başlatırken, bu, Android'in A Aktivitesi için Aktivite A'yı Backstack.eg'e kaydetmesini önleyecektir. Uygulama / Açılış ekranı.

Intent newIntent = new Intent(A.this, B.class);
startActivity(newIntent);
finish();

Durum 2: İkiden fazla faaliyet:

A-> B-> C-> D-> B gibi bir akış varsa ve D Aktivitesinden gelirken B Aktivitesinde geri düğmesine tıkladığınızda bu durumda kullanmalıyız.

Intent newIntent = new Intent(D.this,B.class);
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(newIntent);

Burada Etkinlik B, Intent.FLAG_ACTIVITY_CLEAR_TOP ve Intent.FLAG_ACTIVITY_NEW_TASK nedeniyle yeni bir örnekten ziyade backstack'ten başlatılacak. Geri düğmesine bastığımızda tüm uygulama sonlandırılacak.


2
Bu benim için çalıştı. Bu bayrakları TÜM faaliyetlere koydum. Bu aktivitelerde geri düğmeleri önceki aktiviteye mükemmel şekilde çalışır ve ana Faaliyette Niyet niyetiyle = yeni Niyet (Niyet.ACTION_MAIN); intent.addCategory (Intent.CATEGORY_HOME); intent.addFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK); startActivity (niyet); bitiş(); Tüm uygulama kapalı, hala bellekte ama aktif değil ve u yeniden başlatmak eğer açılış ekranına gider :)
— Rako

Bu en iyi cevap olmalı. Birinin benimle aynı senaryosu varsa: A-> B-> C-> D-> E -> (B) E-> B'nin bir sonucu olmalı: A-> B
— Shem Alexis Chavez

39

Android'in Daha Yeni Sürümü ile = API 16 kullanımı finishAffinity()

yaklaşım> = API 16 için uygundur.

Intent mIntent = new Intent(mContext,MainActivity.class);
finishAffinity();
startActivity(mIntent);
  • Bu, yeni Etkinlik başlatmakla aynıdır ve tüm yığını temizler.
  • VEYA MainActivity / FirstActivity'ye yeniden başlayın.

1
Bu hile yaptı, bayraklar benim için 4.xx üzerinde çalışıyor werent ve bu mükemmel çalıştı! Teşekkürler
— Jonathan Aste

1
Hedefiniz, şu anki etkinlik dahil olmak üzere aşağıdaki tüm etkinlikleri bitirmek ve kendi görevlerinde yeni bir etkinlik başlatmaksa, doğru yanıt bu gibi görünüyor.
— 18'de

24

Bunun için de birkaç saat geçirdim ... ve FLAG_ACTIVITY_CLEAR_TOP'un istediğiniz gibi göründüğünü kabul ediyorum: başlatılan etkinlik dışında tüm yığını temizleyin, böylece Geri düğmesi uygulamadan çıkar. Yine de Mike Repass'ın belirttiği gibi, FLAG_ACTIVITY_CLEAR_TOP yalnızca başlattığınız etkinlik zaten yığıntayken çalışır; etkinlik orada olmadığında, bayrak hiçbir şey yapmaz.

Ne yapalım? Başlatılan etkinliği FLAG_ACTIVITY_NEW_TASK ile yığına koyun, bu da o etkinliği geçmiş yığınında yeni bir görevin başlangıcı yapar. Ardından FLAG_ACTIVITY_CLEAR_TOP bayrağını ekleyin.

Şimdi, FLAG_ACTIVITY_CLEAR_TOP yığındaki yeni etkinliği bulmaya gittiğinde, orada olacak ve her şey temizlenmeden önce kaldırılacak.

İşte çıkış fonksiyonum; View parametresi, işlevin bağlı olduğu düğmedir.

public void onLogoutClick(final View view) {
    Intent i = new Intent(this, Splash.class);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    startActivity(i);
    finish();
}

1
CLEAR_TOP yerine CLEAR_TASK mu demek istediniz?
— Andy

14

Yığını değiştirmemelisiniz. Android geri düğmesi bir web tarayıcısında olduğu gibi çalışmalıdır.

Bunu yapmanın bir yolunu düşünebilirim, ama bu bir hack.

  • Etkinliklerinizi singleTaskÖrneğe ekleyerek gerçekleştirin AndroidManifest :

    <activity android:name=".activities.A"
              android:label="@string/A_title"
              android:launchMode="singleTask"/>
    
    <activity android:name=".activities.B"
              android:label="@string/B_title"
              android:launchMode="singleTask"/>
  • ApplicationNereye gideceğinizin mantığını tutacak şekilde genişletin .

Misal:

public class DontHackAndroidLikeThis extends Application {

  private Stack<Activity> classes = new Stack<Activity>();

  public Activity getBackActivity() {
    return classes.pop();
  }

  public void addBackActivity(Activity activity) {
    classes.push(activity);
  }
}

A'dan B'ye:

DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
app.addBackActivity(A.class); 
startActivity(this, B.class);

B'den C'ye:

DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
app.addBackActivity(B.class); 
startActivity(this, C.class);

C dilinde:

If ( shouldNotGoBackToB() ) {
  DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
  app.pop();
}

ve geri düğmesini pop()yığından tutun .

Bir kez daha, bunu yapmamalısın :)


Sonunda Yığını sağlam bırakmaya ve kullanıcıya mevcut ekranlarının geçersiz olduğunu söylemeye karar verdim
— Casebash

1
Android'in aktivite yığınını bu şekilde yönetmemize izin vermemesi çok sinir bozucu. Gelecekteki android uygulamalarında bu çözümü kullanmak cazip olurdu.
— Cephron

4
Bunun neden kullanılmaması gerektiğinden emin olmak için: bellek sızıntıları oluşturmanın güzel bir yolu. Bir noktada işletim sistemi arka plan etkinliklerini öldürmeye karar verebilir, ancak Applicationörneklerini aldığından beri işletim sistemi yok edilen etkinliklerden kalan RAM'i serbest bırakamaz.
— Vit Khudenko

@Arhimed Başka sorunlar var mı? Bellek sızıntısı yalnızca zayıf referanslar tutularak düzeltilebilir.
— Navin

1
@Navin evet, zayıf ref'lerle sızıntılardan kaçınılabilir, ancak GC'den sonra canlı bir Aktivite ref'si olmayacaksa, tüm yaklaşım işe yaramaz. Bir kez daha - bunu yapma, bu Android için yanlış bir yaklaşımdır.
— Vit Khudenko

12

Düğmesini kullanarak yeni bir etkinliğe başladıktan hemen sonra , geçerli etkinliğin yenisinin arkasında yığılmaması için startActivityaradığınızdan emin olun finish().


+1 Belirli bir durumda tam bir aktivitenin tarih yığınına konmasını önlemek için güzel bir çözüm.
— marsbear

27
yığında birden fazla faaliyet varsa, sonuç sadece önceki etkinliği temizleyecek ancak diğerlerini temizleyecektir ....
— Necronet

5

Bunu dene:

Intent logout_intent = new Intent(DashboardActivity.this, LoginActivity.class);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(logout_intent);
finish();

4

Gelişmiş Yeniden Kullanılabilir Kotlin:

Bayrağı doğrudan ayarlayıcı yöntemini kullanarak ayarlayabilirsiniz. KOTLIN yılında orise yedek Java bitwise veya için |.

intent.flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK

Bunu düzenli olarak kullanmayı planlıyorsanız, bir Intent uzantısı işlevi oluşturun

fun Intent.clearStack() {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}

Ardından, amacı başlatmadan önce doğrudan bu işlevi çağırabilirsiniz

intent.clearStack()

Başka durumlarda ek bayrak ekleme seçeneğine ihtiyacınız varsa, uzantı işlevine isteğe bağlı bir param ekleyin.

fun Intent.clearStack(additionalFlags: Int = 0) {
    flags = additionalFlags or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}

2
Intent i = new Intent(MainPoliticalLogin.this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);

2

Aşağıdaki kodu deneyin,

Intent intent = new Intent(ManageProfileActivity.this, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|
                Intent.FLAG_ACTIVITY_CLEAR_TASK| 
                Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

Bu etkinlik gibi kullanıyorum bir kez daha güncellenir api çağırın ama önceden var olan tüm statck temizlenir
— Harsha

2

Bana İçin hiçbiri yukarıdaki yöntemlerden değil işin.

Önceki tüm etkinlikleri silmek için bunu yapmanız yeterlidir :

finishAffinity() // if you are in fragment use activity.finishAffinity()
Intent intent = new Intent(this, DestActivity.class); // with all flags you want
startActivity(intent)

-1

Bazen android öykünücünüz tutulma DDMS aracını bağlayamayabilir ve adb'nin manuel olarak başlamasını isteyebilir. Bu durumda, komut istemini kullanarak adb'yi başlatabilir veya durdurabilirsiniz.


1
Bazen android öykünücünüz tutulma DDMS aracını bağlayamayabilir ve adb'nin manuel olarak başlamasını isteyebilir. Bu durumda, komut istemini kullanarak adb'yi başlatabilir veya durdurabilirsiniz. Amaç i = yeni Amaç (OldActivity.this, NewActivity.class); // yeni görevi ayarlayın ve bayrakları temizleyin i.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) startActivity (i);
— RajeshkumarG

-2

Çok basit kesmek buldum sadece bu AndroidManifestgibi yeni öğe eklemek yapmak : -

<activity android:name=".activityName"
          android:label="@string/app_name"
          android:noHistory="true"/>

android:noHistoryYığın adresinin istenmeyen aktiviteyi temizleyecektir.


2
Bu Aktivitede izin istersen, bu yaklaşım Android 6.0 ve sonraki sürümlerinde sorunlara neden olabilir.
— Vitaliy A
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.