Bersihkan seluruh tumpukan riwayat dan mulailah aktivitas baru di Android

332

Apakah mungkin untuk memulai suatu kegiatan di tumpukan, membersihkan seluruh riwayat sebelum itu?

Situasi

Saya memiliki tumpukan aktivitas yang berjalan A-> B-> C atau B-> C (layar A memilih token pengguna, tetapi banyak pengguna hanya memiliki token tunggal).

Di layar C pengguna dapat mengambil tindakan yang membuat layar B tidak valid, sehingga aplikasi ingin membawanya ke layar A, terlepas dari apakah itu sudah ada di tumpukan. Layar A seharusnya menjadi satu-satunya item di tumpukan dalam aplikasi saya.

Catatan

Ada banyak pertanyaan serupa lainnya, tetapi saya belum menemukan apa pun yang menjawab pertanyaan persis ini. Saya mencoba menelepon getParent().finish()- ini selalu menghasilkan pengecualian pointer nol. FLAG_ACTIVITY_CLEAR_TOPhanya berfungsi jika aktivitas sudah di stack.

Casebash
sumber

Jawaban:

658

Di API level 11, Bendera Intent baru ditambahkan hanya untuk ini: Intent.FLAG_ACTIVITY_CLEAR_TASK

Hanya untuk memperjelas, gunakan ini:

Jawa

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

Sayangnya untuk API lvl <= 10, saya belum menemukan solusi bersih untuk ini. Solusi "DontHackAndroidLikeThis" memang murni peretasan. Anda seharusnya tidak melakukan itu. :)

Sunting: Sesuai komentar @ Ben Pearson , untuk API <= 10 sekarang orang dapat menggunakan kelas IntentCompat untuk hal yang sama. Seseorang dapat menggunakan IntentCompat.FLAG_ACTIVITY_CLEAR_TASKflag untuk menghapus tugas. Jadi, Anda dapat mendukung pra API level 11 juga.

Akos Cz
sumber
23
Untuk memperjelas, gunakan ini: intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
user123321
2
tanpa Intent.FLAG_ACTIVITY_NEW_TASK aplikasi kadang-kadang hanya menutup sendiri di android 4
max4ever
22
IntentCompat memiliki bendera untuk menghapus tugas sekarang juga, sehingga Anda dapat mendukung pra API level 11 - developer.android.com/reference/android/support/v4/content/…
Ben Pearson
10
IntentCompat.FLAG_ACTIVITY_CLEAR_TASK diabaikan pada perangkat dengan level API <10. developer.android.com/reference/android/support/v4/content/…
David
7
Bendera IntentCompat hanya untuk menghindari kerusakan, tetapi tidak melakukan apa pun seperti yang dikatakan @David.
Sloy
49

Kasus 1: Hanya dua aktivitas A dan B:

Di sini, Alur aktivitas adalah A-> B. Pada mengklik tombol backb dari B kita perlu menutup aplikasi kemudian sambil memulai Aktivitas B dari A just call finish () ini akan mencegah android menyimpan Aktivitas A ke dalam Backstack.eg untuk aktivitas A adalah Layar Loding / Splash aplikasi.

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

Kasus 2: Lebih dari dua kegiatan:

Jika ada aliran seperti A-> B-> C-> D-> B dan mengklik tombol kembali di Kegiatan B saat datang dari Kegiatan D. Dalam hal itu kita harus menggunakan.

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

Di sini Aktivitas B akan dimulai dari backstack daripada contoh baru karena Intent.FLAG_ACTIVITY_CLEAR_TOP dan Intent.FLAG_ACTIVITY_NEW_TASK membersihkan tumpukan dan menjadikannya yang teratas. Jadi ketika kita menekan tombol kembali seluruh aplikasi akan dihentikan.

monish george
sumber
2
Ini berhasil untuk saya. Saya memasukkan SEMUA kegiatan bendera itu. Dalam aktivitas tersebut tombol kembali berfungsi dengan sempurna untuk aktivitas sebelumnya, dan di Aktivitas utama dengan Intent intent = new Intent (Intent.ACTION_MAIN); intent.addCategory (Intent.CATEGORY_HOME); intent.addFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK); startActivity (niat); selesai(); Seluruh aplikasi ditutup, masih dalam memori tetapi tidak aktif, dan jika Anda me-restart aplikasi pergi ke layar splash :)
Rako
Ini harus menjadi jawaban terbaik. Jika ada yang memiliki skenario yang sama dengan saya: A-> B-> C-> D-> E -> (B) Dari E-> B harus memiliki hasil: A-> B
Shem Alexis Chavez
39

Dengan Android Versi Baru> = API 16 digunakan finishAffinity()

pendekatan ini cocok untuk> = API 16.

Intent mIntent = new Intent(mContext,MainActivity.class);
finishAffinity();
startActivity(mIntent);
  • Ini sama dengan memulai Aktivitas baru, dan menghapus semua tumpukan.
  • ATAU Mulai Ulang ke MainActivity / FirstActivity.
karan
sumber
1
Ini berhasil, bendera tidak bekerja pada 4.xx untuk saya dan ini bekerja dengan sempurna! Terima kasih
Jonathan Aste
1
Ini tampaknya menjadi jawaban yang benar jika tujuan Anda adalah untuk menyelesaikan semua kegiatan di bawah ini dan termasuk kegiatan saat ini dan memulai kegiatan baru dalam tugas mereka sendiri.
ToBe
24

Saya menghabiskan beberapa jam untuk hal ini juga ... dan setuju bahwa FLAG_ACTIVITY_CLEAR_TOP terdengar seperti yang Anda inginkan: kosongkan seluruh tumpukan, kecuali untuk aktivitas yang diluncurkan, jadi tombol Kembali keluar dari aplikasi. Namun seperti yang disebutkan Mike Repass, FLAG_ACTIVITY_CLEAR_TOP hanya berfungsi ketika aktivitas yang Anda luncurkan sudah ada di tumpukan; ketika aktivitas tidak ada di sana, bendera tidak melakukan apa-apa.

Apa yang harus dilakukan? Masukkan aktivitas yang diluncurkan di tumpukan dengan FLAG_ACTIVITY_NEW_TASK, yang menjadikan aktivitas itu sebagai awal dari tugas baru di tumpukan riwayat. Kemudian tambahkan flag FLAG_ACTIVITY_CLEAR_TOP.

Sekarang, ketika FLAG_ACTIVITY_CLEAR_TOP pergi untuk mencari aktivitas baru di stack, itu akan ada di sana dan ditarik sebelum semua yang lain dihapus.

Inilah fungsi logout saya; parameter View adalah tombol yang dilampirkan fungsi.

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();
}
pengguna2895402
sumber
1
maksud Anda CLEAR_TASK alih-alih CLEAR_TOP?
Andy
14

Anda tidak harus mengubah tumpukan. Tombol kembali Android seharusnya berfungsi seperti pada browser web.

Saya bisa memikirkan cara untuk melakukannya, tetapi itu cukup hack.

  • Jadikan Aktivitas Anda singleTaskdengan menambahkannya ke AndroidManifest Contoh:

    <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"/>
  • Perluas Applicationyang akan menyimpan logika ke mana harus pergi.

Contoh:

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

Dari A ke B:

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

Dari B ke C:

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

Dalam C:

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

dan menangani tombol kembali ke pop() dari tumpukan.

Sekali lagi, Anda tidak harus melakukan ini :)

Makarse
sumber
Pada akhirnya saya memutuskan untuk meninggalkan Stack utuh dan hanya memberi tahu pengguna bahwa layar mereka saat ini tidak valid
Casebash
1
Sangat frustasi karena android tidak membiarkan kami mengelola aktivitas dengan cara ini. Saya akan tergoda untuk menggunakan solusi ini di aplikasi Android masa depan saya.
Cephron
4
Hanya untuk memperjelas mengapa ini tidak boleh digunakan: ini adalah cara yang bagus untuk membuat kebocoran memori. Pada titik tertentu OS mungkin memutuskan untuk mematikan aktivitas latar belakang, tetapi karena Applicationmengambil contoh mereka, OS tidak akan dapat membebaskan RAM yang tersisa dari aktivitas yang dihancurkan.
Vit Khudenko
@Arhimed Apakah ada masalah lain? Kebocoran memori dapat diperbaiki dengan hanya menyimpan referensi yang lemah.
Navin
1
@Navin ya, kebocoran dapat dihindari dengan referensi lemah, tetapi jika setelah GC tidak akan ada ref Aktivitas langsung maka seluruh pendekatan tidak berguna. Sekali lagi - jangan lakukan ini, ini adalah pendekatan yang salah untuk Android.
Vit Khudenko
12

Segera setelah Anda memulai aktivitas baru, menggunakan startActivity, pastikan Anda menelepon finish()agar aktivitas saat ini tidak ditumpuk di belakang yang baru.

Keith Maurino
sumber
+1 Solusi bagus untuk mencegah satu aktivitas dalam situasi tertentu agar tidak dimasukkan ke tumpukan riwayat.
marsbear
27
tidak berfungsi jika Anda memiliki lebih dari satu aktivitas di tumpukan, penyelesaiannya hanya akan menghapus aktivitas sebelumnya tetapi tidak yang lain ....
Necronet
5

Coba ini:

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();
Mohammad
sumber
4

Kotlin yang Dapat Digunakan Kembali Lanjut:

Anda dapat mengatur bendera secara langsung menggunakan metode penyetel. Di Kotlin oradalah pengganti untuk bitwise Java atau |.

intent.flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK

Jika Anda berencana untuk menggunakan ini secara teratur, buat fungsi ekstensi Intent

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

Anda kemudian dapat langsung memanggil fungsi ini sebelum memulai niat

intent.clearStack()

Jika Anda memerlukan opsi untuk menambahkan flag tambahan dalam situasi lain, tambahkan param opsional ke fungsi ekstensi.

fun Intent.clearStack(additionalFlags: Int = 0) {
    flags = additionalFlags or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
Gibolt
sumber
2
Intent i = new Intent(MainPoliticalLogin.this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
Neeraj Gupta
sumber
2

Coba kode di bawah ini,

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);
shashikant yadav
sumber
jika saya menggunakan aktivitas ini diperbarui sekali lagi panggil api tetapi sebelumnya sudah ada semua statck dihapus
Harsha
2

Bagi saya tidak ada metode di atas tidak berfungsi.

Lakukan ini untuk menghapus semua aktivitas sebelumnya :

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

Terkadang emulator android Anda mungkin gagal menghubungkan alat DDMS eclipse dan meminta adb untuk memulai secara manual. Dalam hal ini Anda dapat memulai atau menghentikan adb menggunakan command prompt.

RajeshkumarG
sumber
1
Terkadang emulator android Anda mungkin gagal menghubungkan alat DDMS eclipse dan meminta adb untuk memulai secara manual. Dalam hal ini Anda dapat memulai atau menghentikan adb menggunakan command prompt. Intent i = Intent baru (OldActivity.this, NewActivity.class); // atur tugas baru dan hapus bendera i.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) startActivity (i);
RajeshkumarG
-2

Saya menemukan hack terlalu sederhana lakukan ini tambahkan elemen baru AndroidManifestsebagai: -

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

yang android:noHistoryakan menghapus aktivitas yang tidak diinginkan Anda dari Stack.

Tauseef
sumber
2
Aproachment ini dapat menyebabkan masalah pada Android 6.0+, jika Anda meminta izin dalam Kegiatan ini.
Vitaliy A