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.