Pertama, saya tahu bahwa seseorang seharusnya tidak benar-benar mematikan / memulai ulang aplikasi di Android. Dalam kasus penggunaan saya, saya ingin mengatur ulang pabrik aplikasi saya dalam kasus tertentu di mana server mengirimkan informasi tertentu ke klien.
Pengguna hanya dapat login di server dengan SATU instance aplikasi (yaitu beberapa perangkat tidak diperbolehkan). Jika instance lain mendapatkan "login" -kunci maka semua instance lain dari pengguna tersebut harus menghapus data mereka (reset pabrik), untuk mempertahankan konsistensi.
Dimungkinkan untuk mendapatkan kunci secara paksa, karena pengguna mungkin menghapus aplikasi dan menginstalnya kembali yang akan menghasilkan id-instance yang berbeda dan pengguna tidak akan dapat membebaskan kunci lagi. Karena itu dimungkinkan untuk mendapatkan kunci secara paksa.
Karena kemungkinan-kekuatan itu kita perlu selalu memeriksa secara konkret bahwa ia memiliki kunci. Itu dilakukan pada (hampir) setiap permintaan ke server. Server mungkin mengirim "salah-kunci-id". Jika itu terdeteksi, aplikasi klien harus menghapus semuanya.
Itu adalah kasus penggunaan.
Saya memiliki nilai Activity
A yang memulai Login Activity
L atau Activity
B utama aplikasi tergantung pada nilai sharedPrefs. Setelah memulai L atau B itu menutup sendiri sehingga hanya L atau B yang berjalan. Jadi dalam hal pengguna sudah masuk B sedang berjalan sekarang.
B dimulai C. C panggilan startService
untuk IntentService
D. Itu hasil di tumpukan ini:
(A)> B> C> D
Dari metode onHandleIntent dari D, sebuah event dikirimkan ke ResultReceiver R.
R sekarang menangani acara itu dengan menyediakan dialog kepada pengguna di mana ia dapat memilih untuk mengatur ulang aplikasi (menghapus database, sharedPrefs, dll.)
Setelah reset pabrik saya ingin me-restart aplikasi (untuk menutup semua aktivitas) dan hanya memulai A lagi yang kemudian meluncurkan login Activity
L dan menyelesaikan sendiri:
(A)> L
Metode onClick Dialog terlihat seperti ini:
@Override
public void onClick(DialogInterface dialog, int which) {
// Will call onCancelListener
MyApplication.factoryReset(); // (Deletes the database, clears sharedPrefs, etc.)
Intent i = new Intent(MyApp.getContext(), A.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MyApp.getContext().startActivity(i);
}
Dan itulah MyApp
kelasnya:
public class MyApp extends Application {
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
public static Context getContext() {
return context;
}
public static void factoryReset() {
// ...
}
}
Masalahnya adalah jika saya menggunakan FLAG_ACTIVITY_NEW_TASK
Aktivitas B dan C masih berjalan. Jika saya menekan tombol kembali pada login Activity
saya melihat C, tetapi saya ingin kembali ke layar beranda.
Jika saya tidak mengatur FLAG_ACTIVITY_NEW_TASK
saya mendapat kesalahan:
07-07 12:27:12.272: ERROR/AndroidRuntime(9512): android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
Saya tidak dapat menggunakan Kegiatan ' Context
, karena ServiceIntent
D juga dapat dipanggil dari tugas latar belakang yang dimulai oleh AlarmManager
.
Jadi bagaimana saya bisa menyelesaikan ini hingga tumpukan aktivitas menjadi (A)> L?
sumber
Anda cukup menelepon:
Yang digunakan di perpustakaan ProcessPhoenix
Sebagai alternatif:
Inilah versi jawaban @Oleg Koshkin yang sedikit lebih baik.
Jika Anda benar-benar ingin memulai kembali aktivitas Anda termasuk penghentian proses saat ini, coba ikuti kode. Tempatkan di HelperClass atau di tempat Anda membutuhkannya.
Ini juga akan menginisialisasi ulang kelas jni dan semua instance statis.
sumber
AlarmManager
dan kesalahan perilaku jika menggunakan solusi ini, Adakah pendekatan yang lebih baik?Jake Wharton baru-baru ini menerbitkan perpustakaan ProcessPhoenix , yang melakukan ini dengan cara yang dapat diandalkan. Anda pada dasarnya hanya perlu menelepon:
Perpustakaan akan secara otomatis menyelesaikan aktivitas panggilan, mematikan proses aplikasi dan memulai kembali aktivitas aplikasi default setelahnya.
sumber
<category android:name="android.intent.category.DEFAULT" />
ke aktivitas default Anda <intent-filter> di manifes aplikasi.Saya telah sedikit memodifikasi jawaban Ilya_Gazman untuk menggunakan API baru (IntentCompat tidak digunakan mulai API 26). Runtime.getRuntime (). Exit (0) tampaknya lebih baik daripada System.exit (0).
sumber
System.exit(n)
secara efektif setara dengan panggilan:Runtime.getRuntime().exit(n)
". Secara internal,System.exit()
hanya berbalik dan meneleponRuntime.getRuntime().exit()
. Tidak ada yang "lebih baik" tentang yang satu atau yang lainnya (kecuali jika ada yang khawatir tentang seberapa banyak yang diketik seseorang atau tentang satu lapisan tambahan panggilan metode).Runtime.getRuntime().exit(0)
(atauSystem.exit(0)
) mungkin akan berfungsi. Beberapa komentar "tidak baik" saya adalah untuk jawaban (seperti yang oleh Ilya Gazman yang sejak itu telah diedit untuk memasukkan panggilan semacam itu.IntentCompat.makeRestartActivityTask
Cara baru untuk melakukannya, adalah dengan menggunakan IntentCompat.makeRestartActivityTask
sumber
Application
objek. Oleh karena itu setiapstatic
data, data yang diinisialisasi selama pembuatanApplication
, atau kelas jni tetap dalam keadaan saat ini dan tidak diinisialisasi ulang.IntentCompat.makeRestartActivityTask
sekarang sudah usang . Jika Anda memeriksa kode sumber , sesederhana menambahkan benderaIntent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
.Ada trik yang sangat bagus. Masalah saya adalah bahwa beberapa perpustakaan C ++ jni benar-benar tua membocorkan sumber daya. Pada titik tertentu, itu berhenti berfungsi. Pengguna mencoba untuk keluar dari aplikasi dan meluncurkannya lagi - tanpa hasil, karena menyelesaikan suatu kegiatan tidak sama dengan menyelesaikan (atau membunuh) proses. (Omong-omong, pengguna dapat masuk ke daftar aplikasi yang sedang berjalan dan menghentikannya dari sana - ini akan berhasil, tetapi pengguna tidak tahu cara menghentikan aplikasi.)
Jika Anda ingin mengamati efek dari fitur ini, tambahkan
static
variabel ke aktivitas Anda dan tambahkan masing-masing, katakanlah, tekan tombol. Jika Anda keluar dari aktivitas aplikasi dan menjalankan aplikasi lagi, variabel statis ini akan mempertahankan nilainya. (Jika aplikasi benar-benar keluar, variabel akan diberi nilai awal.)(Dan saya harus mengomentari mengapa saya tidak ingin memperbaiki bug sebagai gantinya. Perpustakaan ditulis beberapa dekade yang lalu dan membocorkan sumber daya sejak saat itu. Manajemen percaya itu selalu berhasil . Biaya menyediakan perbaikan bukan solusi ... Saya pikir, Anda mendapatkan idenya.)
Sekarang, bagaimana saya bisa mereset pustaka jni shared (alias dynamic, .so) ke keadaan awal? Saya memilih untuk memulai kembali aplikasi sebagai proses baru.
Kuncinya adalah System.exit () menutup aktivitas saat ini dan Android membuat ulang aplikasi dengan satu aktivitas lebih sedikit.
Jadi kodenya adalah:
Aktivitas panggilan hanya mengeksekusi kode
MagicAppRestart.doRestart(this);
, aktivitas panggilanonPause()
dieksekusi, dan kemudian proses dibuat kembali. Dan jangan lupa untuk menyebutkan kegiatan ini di AndroidManifest.xmlKeuntungan dari metode ini adalah tidak ada penundaan.
UPD: itu bekerja di Android 2.x, tetapi di Android 4 ada sesuatu yang berubah.
sumber
System.exit(0)
denganandroid.os.Process.killProcess(android.os.Process.myPid());
? 2) infinite loop kemungkinan besar berarti mereka tidak menghapus aktivitas paling atas ketika mereka me-restart aplikasi. Pada prinsipnya, Anda dapat menambahkan variabel boolean statis, mengaturnya menjadi true sebelum menjalankan aktivitas restart, dan setelah restart itu akan salah. Dengan demikian aktivitas dapat mengetahui apakah restart telah terjadi (dan jika sudah terjadi, cukup selesaikan () ). OTOH, laporan Anda berarti bahwa trik itu tidak berfungsi secara identik pada semua perangkat.Solusi saya tidak memulai kembali proses / aplikasi. Itu hanya memungkinkan aplikasi "memulai kembali" aktivitas rumah (dan mengabaikan semua aktivitas lainnya). Sepertinya restart untuk pengguna, tetapi prosesnya sama. Saya pikir dalam beberapa kasus orang ingin mencapai efek ini, jadi saya tinggalkan saja di sini FYI.
sumber
Oke, saya refactored aplikasi saya dan saya tidak akan menyelesaikan A secara otomatis. Saya membiarkan ini berjalan selalu dan menyelesaikannya melalui
onActivityResult
acara tersebut. Dengan cara ini saya bisa menggunakan tandaFLAG_ACTIVITY_CLEAR_TOP
+FLAG_ACTIVITY_NEW_TASK
untuk mendapatkan yang saya inginkan:dan di
ResultReceiver
Bagaimanapun, terima kasih!
sumber
sumber
Satu-satunya kode yang tidak memicu "Aplikasi Anda ditutup secara tidak terduga" adalah sebagai berikut. Ini juga kode yang tidak usang yang tidak memerlukan perpustakaan eksternal. Itu juga tidak memerlukan timer.
sumber
Saya telah menemukan bahwa ini berfungsi pada API 29 dan yang lebih baru - untuk tujuan membunuh dan memulai ulang aplikasi seolah-olah pengguna telah meluncurkannya ketika tidak berjalan.
Itu dilakukan ketika aktivitas peluncur di aplikasi memiliki ini:
Saya telah melihat komentar yang mengklaim bahwa kategori DEFAULT diperlukan, tetapi saya belum menemukan itu yang menjadi masalahnya. Saya telah mengkonfirmasi bahwa objek Aplikasi di aplikasi saya dibuat ulang, jadi saya percaya bahwa proses tersebut benar-benar telah dimatikan dan dimulai ulang.
Satu-satunya tujuan yang saya gunakan ini adalah untuk me-restart aplikasi setelah pengguna telah mengaktifkan atau menonaktifkan pelaporan kerusakan untuk Firebase Crashlytics. Menurut dokumen mereka, aplikasi harus dihidupkan ulang (proses dibunuh dan dibuat ulang) agar perubahan itu berlaku.
sumber
Cara terbaik untuk me-restart aplikasi sepenuhnya adalah untuk meluncurkan kembali, bukan hanya untuk melompat ke suatu aktivitas dengan
FLAG_ACTIVITY_CLEAR_TOP
danFLAG_ACTIVITY_NEW_TASK
. Jadi solusi saya adalah melakukannya dari aplikasi Anda atau bahkan dari aplikasi lain, satu-satunya syarat adalah mengetahui nama paket aplikasi (contoh: ' com.example.myProject ')Contoh penggunaan, restart atau luncurkan appA dari appB :
Anda dapat memeriksa apakah aplikasi sedang berjalan:
Catatan : Saya tahu jawaban ini sedikit keluar dari topik, tetapi bisa sangat membantu bagi seseorang.
sumber
Cara terbaik saya untuk me-restart aplikasi adalah menggunakan
finishAffinity();
Sejak,
finishAffinity();
dapat digunakan pada versi JELLY BEAN saja, sehingga kita dapat menggunakanActivityCompat.finishAffinity(YourCurrentActivity.this);
untuk versi yang lebih rendah.Kemudian gunakan
Intent
untuk meluncurkan aktivitas pertama, sehingga kode akan terlihat seperti ini:Semoga ini bisa membantu.
sumber
Coba gunakan
FLAG_ACTIVITY_CLEAR_TASK
sumber
Berikut adalah contoh untuk memulai ulang aplikasi Anda secara umum dengan menggunakan PackageManager:
sumber
Application
objek. Oleh karena itu setiap data statis, data yang diinisialisasi selama pembuatanApplication
, atau kelas jni tetap dalam keadaan saat ini dan tidak diinisialisasi ulang.coba ini:
sumber
Langsung mulai Layar Awal dengan
FLAG_ACTIVITY_CLEAR_TASK
danFLAG_ACTIVITY_NEW_TASK
.sumber
Saya harus menambahkan Handler untuk menunda keluar:
sumber
Menggunakan:
Ia bekerja mulai dari API level 16 (4.1), saya percaya.
sumber
Anda dapat menggunakan
startInstrumentation
metodeActivity
. Anda perlu mengimplementasikan kosongInstrumentation
dan menunjuk dalam manifes. Setelah itu, Anda dapat memanggil metode ini untuk memulai kembali aplikasi Anda. Seperti ini:Saya mendapatkan nama kelas Instrumentasi secara dinamis tetapi Anda dapat meng-hardcode-nya. Beberapa menyukai ini:
Hubungi
startInstrumentation
make reload dari aplikasi Anda. Baca deskripsi metode ini. Tapi itu bisa tidak aman jika bertingkah seperti membunuh aplikasi.sumber
Aplikasi yang sedang saya kerjakan harus memberi pengguna kemungkinan untuk memilih fragmen mana yang akan ditampilkan (fragmen diubah secara dinamis saat run-time). Solusi terbaik bagi saya adalah me- restart sepenuhnya aplikasi .
Jadi saya mencoba banyak solusi dan tidak ada yang bekerja untuk saya, tetapi ini:
Berharap itu akan membantu orang lain!
sumber
coba ini:
sumber
Dengan perpustakaan Proses Phoenix . Aktivitas yang ingin Anda luncurkan kembali dinamai "A".
Rasa Jawa
Rasa Kotlin
sumber
Anda dapat memulai kembali aktivitas Anda saat ini seperti ini:
Pecahan :
Aktivitas :
sumber