Saya bingung di sini .. mengapa android tidak bisa memberikan penggantian sederhana pada kelas aplikasi untuk ini? Apakah terlalu sulit untuk mengetahui ini di tingkat platform? @Override protected void onApplicationSentToBackground () {}
Chuck D
2
@ ChuckD - itu masuk akal, yang sepertinya ingin dilakukan SDK Android. : /
iOS memiliki ini dalam sekop, tidak yakin mengapa Google membuat ini sangat sulit. Ini kebutuhan yang jelas.
Jerry Destremps
Jawaban:
388
Ada beberapa cara untuk mendeteksi apakah aplikasi Anda berjalan di latar belakang, tetapi hanya satu di antaranya yang benar-benar dapat diandalkan:
Solusi yang tepat (kredit pergi ke Dan , CommonsWare dan NeTeInStEiN )
Melacak visibilitas aplikasi Anda sendiri menggunakan Activity.onPause, Activity.onResumemetode. Simpan status "visibilitas" di beberapa kelas lain. Pilihan yang baik adalah implementasi Anda sendiri dari Applicationa atau Service(ada juga beberapa variasi dari solusi ini jika Anda ingin memeriksa visibilitas aktivitas dari layanan).
Contoh
Terapkan Applicationkelas khusus (perhatikan isActivityVisible()metode statis):
Tambahkan onPausedan onResumeke setiap Activityproyek (Anda dapat membuat leluhur bersama untuk Aktivitas Anda jika Anda mau, tetapi jika aktivitas Anda sudah diperluas dari MapActivity/ ListActivitydll. Anda masih perlu menulis yang berikut dengan tangan):
Pembaruan ActivityLifecycleCallbacks ditambahkan di API level 14 (Android 4.0). Anda dapat menggunakannya untuk melacak apakah aktivitas aplikasi Anda saat ini terlihat oleh pengguna. Lihat jawaban Cornstalks di bawah ini untuk detailnya.
Yang salah
saya dulu menyarankan solusi berikut:
Anda dapat mendeteksi aplikasi latar depan / latar belakang saat ini ActivityManager.getRunningAppProcesses()yang mengembalikan daftar RunningAppProcessInfocatatan. Untuk menentukan apakah aplikasi Anda berada di RunningAppProcessInfo.importancebidang cek latar depan untuk persamaan RunningAppProcessInfo.IMPORTANCE_FOREGROUNDsementara RunningAppProcessInfo.processNamesama dengan nama paket aplikasi Anda.
Juga jika Anda menelepon ActivityManager.getRunningAppProcesses()dari utas UI aplikasi Anda, itu akan menjadi penting IMPORTANCE_FOREGROUNDuntuk tugas Anda, tidak peduli apakah itu benar-benar di latar depan atau tidak. Sebut saja di utas latar belakang (misalnya via AsyncTask) dan itu akan mengembalikan hasil yang benar.
Meskipun solusi ini mungkin berhasil (dan memang berfungsi sebagian besar waktu), saya sangat menyarankan untuk tidak menggunakannya. Dan inilah alasannya. Seperti yang ditulis oleh Dianne Hackborn :
API ini tidak ada untuk aplikasi berdasarkan aliran UI mereka, tetapi untuk melakukan hal-hal seperti menunjukkan pengguna aplikasi yang sedang berjalan, atau manajer tugas, atau semacamnya.
Ya ada daftar yang disimpan dalam memori untuk hal-hal ini. Namun, ini tidak aktif dalam proses lain, dikelola oleh utas yang berjalan secara terpisah dari Anda, dan bukan sesuatu yang dapat Anda andalkan (a) melihat pada waktunya untuk membuat keputusan yang benar atau (b) memiliki gambaran yang konsisten pada saat Anda kembali. Ditambah keputusan tentang apa kegiatan "berikutnya" untuk pergi selalu dilakukan pada titik di mana saklar akan terjadi, dan tidak sampai titik yang tepat (di mana keadaan aktivitas secara singkat dikunci untuk melakukan saklar) yang kami sebenarnya tahu pasti apa yang akan terjadi selanjutnya.
Dan implementasi dan perilaku global di sini tidak dijamin tetap sama di masa depan.
Saya berharap saya telah membaca ini sebelum saya memposting jawaban di SO, tapi mudah-mudahan tidak terlambat untuk mengakui kesalahan saya.
Solusi yang salah lagi Droid-Fu perpustakaan disebutkan dalam salah satu penggunaan jawaban ActivityManager.getRunningTasksuntuk yang isApplicationBroughtToBackgroundmetode. Lihat komentar Dianne di atas dan jangan gunakan metode itu juga.
Untuk mengetahui apakah Anda menekan tombol beranda atau aplikasi lain telah mendapatkan fokus: 1) menerapkan solusi yang baik . 2) Dalam OnStoppermintaan untuk isActivityVisible.
Brais Gabin
28
Sayangnya solusi 'benar' Anda tidak berfungsi untuk saya. Pertimbangkan Anda menggilir kegiatan di dalam aplikasi Anda. Apa yang terjadi kemudian adalah bahwa bendera 'inForeground' Anda berjalan seperti ini: Benar, Salah (Antara onPause aktivitas 1 dan onResume aktivitas 2) lalu True lagi, dll. Anda kemudian akan memerlukan semacam histeresis.
Radu
14
Solusi ini tidak berfungsi jika Anda tidak dapat langsung mengontrol semua aktivitas. Misalnya jika Anda memiliki Kegiatan dari sdk pihak ke-3 atau bahkan meluncurkan maksud ACTION_VIEW.
user123321
66
Android adalah bangkai yang sangat menakutkan. Tidak ada yang mengira bahwa seseorang mungkin ingin mempertahankan data tingkat aplikasi? Beri saya istirahat
8
Sepertinya jawaban sebenarnya untuk pertanyaan ini adalah "Anda tidak dapat memeriksanya dengan benar". Solusi yang disebut 'benar' adalah solusi yang terbaik, jadi gunakan ActivityLifecycleCallbacks. Anda masih perlu mempertimbangkan untuk beralih antar kegiatan yang akan didaftarkan sebagai "tidak di latar depan". Saya terpikir bahwa Anda tidak dapat memeriksa hal sederhana seperti itu ...
Saya akan meninggalkan jawaban asli saya di sini demi anak cucu. Ini adalah yang terbaik yang tersedia kembali pada tahun 2012, tetapi sekarang Android memiliki dukungan yang tepat untuk ini.
Jawaban asli
Kuncinya adalah menggunakan ActivityLifecycleCallbacks(perhatikan bahwa ini membutuhkan Android API level 14 (Android 4.0)). Periksa apakah jumlah kegiatan yang dihentikan sama dengan jumlah kegiatan yang dimulai. Jika mereka sama, aplikasi Anda sedang di-background. Jika ada lebih banyak kegiatan yang dimulai, aplikasi Anda masih terlihat. Jika ada lebih banyak aktivitas yang dilanjutkan dari yang dijeda, aplikasi Anda tidak hanya terlihat, tetapi juga ada di latar depan. Ada 3 status utama yang dapat diikuti aktivitas Anda: terlihat dan di latar depan, terlihat tetapi tidak di latar depan, dan tidak terlihat dan tidak di latar depan (yaitu di latar belakang).
Hal yang sangat menyenangkan tentang metode ini adalah tidak memiliki masalah asinkron getRunningTasks(), tetapi Anda juga tidak perlu memodifikasi setiap Activityaplikasi Anda untuk mengatur / menghapus sesuatu di onResumed()/ onPaused(). Ini hanya beberapa baris kode yang lengkap, dan berfungsi di seluruh aplikasi Anda. Plus, tidak ada izin funky yang diperlukan juga.
MyLifecycleHandler.java:
publicclassMyLifecycleHandlerimplementsActivityLifecycleCallbacks{// I use four separate variables here. You can, of course, just use two and// increment/decrement them instead of using four and incrementing them all.privateint resumed;privateint paused;privateint started;privateint stopped;@Overridepublicvoid onActivityCreated(Activity activity,Bundle savedInstanceState){}@Overridepublicvoid onActivityDestroyed(Activity activity){}@Overridepublicvoid onActivityResumed(Activity activity){++resumed;}@Overridepublicvoid onActivityPaused(Activity activity){++paused;
android.util.Log.w("test","application is in foreground: "+(resumed > paused));}@Overridepublicvoid onActivitySaveInstanceState(Activity activity,Bundle outState){}@Overridepublicvoid onActivityStarted(Activity activity){++started;}@Overridepublicvoid onActivityStopped(Activity activity){++stopped;
android.util.Log.w("test","application is visible: "+(started > stopped));}// If you want a static function you can use to check if your application is// foreground/background, you can use the following:/*
// Replace the four variables above with these four
private static int resumed;
private static int paused;
private static int started;
private static int stopped;
// And these two public static functions
public static boolean isApplicationVisible() {
return started > stopped;
}
public static boolean isApplicationInForeground() {
return resumed > paused;
}
*/}
MyApplication.java:
// Don't forget to add it to your manifest by doing// <application android:name="your.package.MyApplication" ...publicclassMyApplicationextendsApplication{@Overridepublicvoid onCreate(){// Simply add the handler, and that's it! No need to add any code// to every activity. Everything is contained in MyLifecycleHandler// with just a few lines of code. Now *that's* nice.
registerActivityLifecycleCallbacks(newMyLifecycleHandler());}}
@Mewzer telah mengajukan beberapa pertanyaan bagus tentang metode ini yang ingin saya balas dalam jawaban ini untuk semua orang:
onStop()tidak dipanggil dalam situasi memori rendah; apakah itu masalah di sini?
Tidak. Dokumen untuk onStop()mengatakan:
Perhatikan bahwa metode ini mungkin tidak pernah dipanggil, dalam situasi memori rendah di mana sistem tidak memiliki cukup memori untuk menjaga proses aktivitas Anda berjalan setelah metode onPause () dipanggil.
Kuncinya di sini adalah "menjaga proses aktivitas Anda berjalan ..." Jika situasi dengan memori rendah ini pernah tercapai, proses Anda sebenarnya terbunuh (bukan hanya aktivitas Anda). Ini berarti bahwa metode ini memeriksa latar belakang masih berlaku karena a) Anda tetap tidak dapat memeriksa latar belakang jika proses Anda mati, dan b) jika proses Anda mulai lagi (karena aktivitas baru dibuat), anggota variabel (apakah statis atau tidak) untuk MyLifecycleHandlerakan diatur ulang ke 0.
Apakah ini berfungsi untuk perubahan konfigurasi?
Secara default, tidak. Anda harus secara eksplisit mengatur configChanges=orientation|screensize( |dengan apa pun yang Anda inginkan) dalam file manifes Anda dan menangani perubahan konfigurasi, atau aktivitas Anda akan dihancurkan dan diciptakan kembali. Jika Anda tidak menetapkan ini, metode aktivitas Anda akan disebut dalam urutan ini: onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume. Seperti yang Anda lihat, tidak ada tumpang tindih (biasanya, dua aktivitas tumpang tindih sangat singkat ketika beralih di antara keduanya, yang merupakan cara kerja metode deteksi latar ini). Untuk mengatasi ini, Anda harus mengatur di semua proyek saya karena itu tidak diinginkan untuk seluruh aktivitas saya untuk dihancurkan di rotate / ubah ukuran layar, jadi saya tidak pernah menemukan ini menjadi bermasalah. (terima kasih kepada dpimka karena menyegarkan ingatan saya tentang ini dan mengoreksi saya!)configChanges agar aktivitas Anda tidak hancur. Untungnya, saya harus mengaturconfigChanges
Satu catatan:
Ketika saya mengatakan "latar belakang" di sini dalam jawaban ini, maksud saya "aplikasi Anda tidak lagi terlihat." Aktivitas Android dapat terlihat namun tidak di latar depan (misalnya, jika ada hamparan notifikasi transparan). Itu sebabnya saya memperbarui jawaban ini untuk mencerminkan hal itu.
Penting untuk mengetahui bahwa Android memiliki momen limbo yang aneh ketika berganti aktivitas di mana tidak ada yang ada di latar depan . Untuk alasan ini, jika Anda memeriksa apakah aplikasi Anda berada di latar depan saat beralih di antara berbagai aktivitas (dalam aplikasi yang sama), Anda akan diberitahu bahwa Anda tidak berada di latar depan (meskipun aplikasi Anda masih merupakan aplikasi yang aktif dan terlihat. ).
Anda dapat memeriksa apakah aplikasi Anda di latar depan di Anda Activity's onPause()metode setelahsuper.onPause() . Hanya ingat keadaan limbo aneh yang baru saja saya bicarakan.
Anda dapat memeriksa apakah aplikasi Anda terlihat (yaitu jika tidak di latar belakang) di Anda Activity's onStop()metode setelahsuper.onStop() .
Ini terlihat menarik - tetapi apa yang terjadi dalam situasi memori rendah? Tidak dijamin bahwa onStop () akan dipanggil. Bisakah kita masuk ke situasi di mana onStop () tidak dipanggil dan penghitung berhenti tidak bertambah - ini berarti bahwa pemeriksaan latar belakang tidak lagi dapat diandalkan? Atau apakah ini tidak akan pernah terjadi?
Mewzer
1
Juga, apakah ini akan mengabaikan perubahan konfigurasi? Atau apakah aplikasi akan dianggap berlatar belakang jika suatu aktivitas dibuat kembali sebagai akibat dari perubahan konfigurasi (mis. Ubah orientasi) ?. Maaf, untuk pertanyaan tapi saya pikir Anda tertarik pada sesuatu dan tertarik untuk mengetahui apakah itu berfungsi dalam kasus tepi ini.
Mewzer
1
@Mewzer: Saya akan merespons sebagai komentar, tetapi perlu sedikit pengetikan untuk mendapatkan jawaban ini, jadi periksa kembali dalam beberapa menit dan saya akan mengedit jawaban saya.
Cornstalks
1
@Mewzer: Anda harus menemukan jawaban Anda sekarang. Beri tahu saya jika ada pertanyaan lain!
Cornstalks
2
@Mewzer: Saya baru saja menambahkan catatan bahwa Anda mungkin tertarik. Secara khusus, periksa latar belakang onStop()setelah super.onStop(). Jangan periksa latar belakang di onPause().
Cornstalks
187
SOLUSI GOOGLE - bukan peretasan, seperti solusi sebelumnya. Gunakan ProcessLifecycleOwner
Kotlin:
classArchLifecycleApp:Application(),LifecycleObserver{override fun onCreate(){super.onCreate()ProcessLifecycleOwner.get().lifecycle.addObserver(this)}@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onAppBackgrounded(){//App in background}@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onAppForegrounded(){// App in foreground}}
Jawa:
publicclassArchLifecycleAppextendsApplicationimplementsLifecycleObserver{@Overridepublicvoid onCreate(){super.onCreate();ProcessLifecycleOwner.get().getLifecycle().addObserver(this);}@OnLifecycleEvent(Lifecycle.Event.ON_STOP)publicvoid onAppBackgrounded(){//App in background}@OnLifecycleEvent(Lifecycle.Event.ON_START)publicvoid onAppForegrounded(){// App in foreground}}
di app.gradle
dependencies {...
implementation "android.arch.lifecycle:extensions:1.1.0"//New Android X dependency is this -
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"}
allprojects {
repositories {...
google()
jcenter()
maven { url 'https://maven.google.com'}}}
Ini pasti jawaban yang benar! Itu bekerja seperti pesona: D
JaviOverflow
2
Ini berfungsi dengan baik, saya juga sedikit dimodifikasi sehingga saya bisa mengakses keadaan latar depan / latar belakang lebih mudah di luar kelas ini: companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }maka Anda bisa mendapatkan latar latar depan denganArchLifecycleApp.isForeground()
Jose Jet
2
Oh man, ini jauh lebih baik daripada jawaban lamaku. Dapatkan +1 dari saya. Saya memperbarui jawaban saya untuk mengarahkan orang kepada Anda.
Cornstalks
2
Meskipun ini adalah jawaban yang benar, tidak perlu menerapkan panggilan balik, Anda bisa saja meminta ProcessLifecycleOwner kapan pun Anda mau. Periksa stackoverflow.com/a/52678290/6600000
Keivan Esbati
2
Seperti kata doc The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes. , ini tidak berfungsi untuk multiple processesaplikasi, adakah api yang bisa kita raih dengan elegan?
acntwww
23
Memulai pustaka dukungan versi 26 Anda dapat menggunakan ProcessLifecycleOwner , cukup tambahkan ke dependensi Anda seperti dijelaskan di sini , misalnya:
dependencies {def lifecycle_version ="1.1.1"// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:$lifecycle_version"// alternatively - Lifecycles only (no ViewModel or LiveData).// Support library depends on this lightweight import
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"// use kapt for Kotlin}
Dan kemudian kueri ProcessLifecycleOwnerkapan saja Anda ingin status aplikasi, contoh:
//Check if app is in backgroundProcessLifecycleOwner.get().getLifecycle().getCurrentState()==Lifecycle.State.CREATED;//Check if app is in foregroundProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
Terima kasih kawan, ini adalah cara terbaik dan termudah yang cocok di bagian mana pun dari kode Anda khususnya ketika menggunakan fcm.
Mihae Kheel
jika aplikasi ditutup sepenuhnya apa yang akan mengembalikan metode pertama?
Evgeniy Mishustin
@ EvgeniyMishustin yang tergantung pada kondisi aplikasi saat ini, tetapi Anda biasanya akan melihat DIBUAT kemudian DIHANCURKAN dan setelah itu, Anda tidak akan menerima acara baru.
Keivan Esbati
Jadi di mana ada pernyataan "JIKA" untuk melihat JIKA aplikasi di latar belakang (latar depan) ???
ekashking
@ekashking cukup masukkan seluruh pernyataan dalam if-clause. Misalnya: if (ProcessLifecycleOwner.get (). GetLifecycle (). GetCurrentState (). IsAtLeast (Lifecycle.State.STARTED)) => Aplikasi ada di latar depan
Keivan Esbati
20
Sejak Android API 16 ada cara sederhana untuk memeriksa apakah aplikasi di latar depan. Mungkin tidak mudah, tetapi tidak ada metode di Android yang sangat mudah. Metode ini cukup baik untuk digunakan ketika layanan Anda menerima pembaruan dari server dan harus memutuskan apakah akan menampilkan pemberitahuan, atau tidak (karena jika UI adalah latar depan, pengguna akan melihat pembaruan tanpa pemberitahuan).
haruskah kode ini berada di dalam kelas Layanan atau kelas lain misalnya kelas Aplikasi? Terima kasih banyak.
Woppi
.. dimanapun Anda ingin menggunakannya sebagai baris terakhir hanya boolean yang akan Anda periksa.
AO_
Ini adalah metodologi yang sama dengan AWS Android SDK untuk pemberitahuan push.
spakmad
Ketahuilah bahwa "Definisi latar belakang untuk tujuan pembatasan layanan berbeda dari definisi yang digunakan oleh manajemen memori; aplikasi mungkin di latar belakang berkaitan dengan manajemen memori, tetapi di latar depan berkaitan dengan kemampuannya untuk meluncurkan layanan.) " developer.android.com/about/versions/oreo/background.html (
ARLabs
Terima kasih, ini berhasil! Saya dapat menggunakan kode ini JobServiceuntuk mendeteksi bahwa layanan berjalan di latar belakang.
Idolon's answer is error prone- sayangnya saya harus setuju dengan Anda. Berdasarkan komentar Dianne Hackborn di Grup Google, saya telah memperbarui jawaban saya. Silakan periksa detailnya.
Idolon
2
Ini juga bukan solusi yang mudah. Salah satu skenario adalah jika pengguna ditarik ke bawah panel notifikasi, maka tidak dengan onPause, onStop, maupun onResumeacara disebut. Jadi, apa yang Anda lakukan jika tidak ada acara yang dipecat ?!
Sedihnya, tetapi kode ini bekerja salah ketika suatu kegiatan dimulai ketika layar mati. Dalam hal ini onResume dan onPause disebut membuat isVisible = false.
CoolMind
@CoolMind Bisakah Anda jelaskan apa kasus penggunaan di mana Anda akan memulai suatu kegiatan di latar belakang?
neteinstein
11
Saya mencoba solusi yang disarankan yang menggunakan Application.ActivityLifecycleCallbacks dan banyak lainnya, tetapi mereka tidak berfungsi seperti yang diharapkan. Berkat Sarge , saya datang dengan solusi yang cukup mudah dan langsung yang saya jelaskan di bawah ini.
Mereka kunci dari solusi adalah fakta pemahaman bahwa jika kita memiliki ActivityA dan ActivityB, dan kita sebut ActivityB dari ActivityA (dan bukan panggilan ActivityA.finish), maka ActivityB onStart()akan dipanggil sebelum ActivityA onStop().
Itu juga perbedaan utama antara onStop()dan onPause()yang tidak disebutkan dalam artikel yang saya baca.
Jadi berdasarkan perilaku Siklus Hidup Kegiatan ini, Anda dapat menghitung berapa kali dilakukan onStart()dan onPause()dipanggil dalam program Anda. Perhatikan bahwa untuk setiapActivity program Anda, Anda harus mengganti onStart()dan onStop(), untuk menambah / mengurangi variabel statis yang digunakan untuk menghitung. Di bawah ini adalah kode yang mengimplementasikan logika ini. Perhatikan bahwa saya menggunakan kelas yang diperluas Application, jadi jangan lupa untuk mendeklarasikan di Manifest.xmldalam tag Aplikasi:, android:name=".Utilities"meskipun dapat diimplementasikan menggunakan kelas kustom yang sederhana juga.
publicclassUtilitiesextendsApplication{privatestaticint stateCounter;publicvoid onCreate(){super.onCreate();
stateCounter =0;}/**
* @return true if application is on background
* */publicstaticboolean isApplicationOnBackground(){return stateCounter ==0;}//to be called on each Activity onStart()publicstaticvoid activityStarted(){
stateCounter++;}//to be called on each Activity onStop()publicstaticvoid activityStopped(){
stateCounter--;}}
Sekarang pada setiap Kegiatan program kami, kami harus mengganti onStart()dan onStop()dan menambah / mengurangi seperti yang ditunjukkan di bawah ini:
@Overridepublicvoid onStart(){super.onStart();Utilities.activityStarted();}@Overridepublicvoid onStop(){Utilities.activityStopped();if(Utilities.isApplicationOnBackground()){//you should want to check here if your application is on background}super.onStop();}
Dengan logika ini, ada 2 kemungkinan kasus:
stateCounter = 0 : Jumlah yang dihentikan sama dengan jumlah Aktivitas yang dimulai, yang berarti bahwa aplikasi sedang berjalan di latar belakang.
stateCounter > 0 : Jumlah awal lebih besar dari jumlah berhenti, yang berarti bahwa aplikasi sedang berjalan di latar depan.
Memperhatikan: stateCounter < 0 akan berarti bahwa ada lebih banyak Kegiatan yang berhenti daripada dimulai, yang tidak mungkin. Jika Anda menemukan kasus ini, berarti Anda tidak menambah / mengurangi penghitung seperti yang seharusnya.
Kamu siap untuk pergi. Anda harus memeriksa apakah aplikasi Anda berada di latar belakang dalamnya onStop().
Saya akan pindah if(Utilities.isApplicationOnBackground()) …ke Utilities. Karena kalau tidak, hanya aktivitas tertentu yang akan bereaksi pada acara tersebut.
Nama Tampilan
10
Tidak mungkin, singkat dari Anda melacaknya sendiri, untuk menentukan apakah ada aktivitas Anda yang terlihat atau tidak. Mungkin Anda harus mempertimbangkan untuk mengajukan pertanyaan StackOverflow baru, menjelaskan apa yang ingin Anda capai dari pengalaman pengguna, jadi kami mungkin dapat memberikan Anda ide-ide implementasi alternatif.
Di android, kami memiliki pengaturan yang disebut "Data Latar Belakang". Pengaturan ini mengubah setiap koneksi data latar belakang saat aplikasi berjalan di latar belakang. Saya ingin menerapkan toggle "Data latar belakang" untuk aplikasi saya, jadi ketika tidak ada aktivitas saya yang terlihat oleh pengguna, saya ingin layanan saya berhenti melakukan transfer data apa pun, tetapi saat salah satu aktivitas saya berlanjut, saya ingin melanjutkan transfer data
cppdev
1
@cppdev: Semoga "transfer data" sedang dilakukan oleh a Service. Jika demikian, mintalah kegiatan Anda memberi tahu layanan tersebut ketika mereka muncul dan menghilang. Jika Servicemenentukan bahwa tidak ada kegiatan yang terlihat, dan tetap seperti itu selama beberapa waktu, hentikan transfer data pada titik penghentian logis berikutnya. Ya, ini akan memerlukan kode untuk setiap aktivitas Anda, tetapi saat ini, itu adalah AFAIK yang tidak dapat dihindari.
CommonsWare
1
Jika Anda ingin menghindari menyalin-tempel kode umum di antara semua aktivitas Anda, Anda dapat membuat kelas yang MyActivityClassmewarisi dari Activitydan menerapkan metode siklus hidup, dan membuat semua aktivitas Anda mewarisi dari MyActivityClass. Ini tidak akan bekerja untuk PreferenceActivityatau MapActivitymeskipun (lihat pertanyaan ini )
Guillaume Brunerie
@CommonsWare saya sudah mencoba dengan OnPause () OnResume () apakah itu aktif atau tidak, tetapi jika aplikasi saya tidak dapat melihat di layar tampilan jika berjalan di latar belakang bagaimana memeriksa apakah itu aktif atau tidak
Manoj
@CommonsWare saya telah mencoba dengan OnPause () OnResume () apakah itu aktif atau tidak, tetapi jika aplikasi saya tidak dapat melihat di layar tampilan jika berjalan di latar belakang bagaimana memeriksa apakah itu aktif atau tidak
Manoj
5
Anda dapat menggunakan ComponentCallbacks2 untuk mendeteksi jika aplikasi di latar belakang. BTW panggilan balik ini hanya tersedia di API Level 14 (Ice Cream Sandwich) dan di atasnya.
Anda akan mendapatkan panggilan ke metode:
public abstract void onTrimMemory (int level)
jika levelnya ComponentCallbacks2.TRIM_MEMORY_UI_HIDDENmaka aplikasi di latar belakang.
Anda dapat mengimplementasikan interface ini ke activity, service, dll
publicclassMainActivityextendsAppCompatActivityimplementsComponentCallbacks2{@Overridepublicvoid onConfigurationChanged(finalConfiguration newConfig){}@Overridepublicvoid onLowMemory(){}@Overridepublicvoid onTrimMemory(finalint level){if(level ==ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){// app is in background}}}
Sudah mencoba jawaban Anda tetapi tidak bisa diandalkan. panggilan balik onTrimMemory tidak akan terpicu ketika layar terkunci atau ketika menekan tombol "power" untuk mengunci layar. Itu juga tidak akan selalu mengembalikan TRIM_MEMORY_UI_HIDDEN jika aplikasi Anda terlihat dan Anda membuka aplikasi lain melalui pemberitahuan bilah status. Satu-satunya solusi yang dapat diandalkan adalah mengimplementasikan ActivityLifecycleCallbacks dan menyesuaikannya dengan case use.
velval
4
Membangun @Cornstalks menjawab untuk menyertakan beberapa fitur yang bermanfaat.
Fitur tambahan:
memperkenalkan pola singleton sehingga Anda dapat melakukan ini di mana saja dalam aplikasi: AppLifecycleHandler.isApplicationVisible () dan AppLifecycleHandler.isApplicationInForeground ()
penanganan tambahan pada acara duplikat (lihat komentar // ambil tindakan atas perubahan visibilitas dan // ambil tindakan atas perubahan di latar depan)
Solusi terbaik yang saya miliki dengan menggunakan timer.
Anda telah memulai timer di onPause () dan membatalkan timer yang sama di onResume (), ada 1 instance dari Timer (biasanya didefinisikan dalam kelas Aplikasi). Timer itu sendiri diatur untuk menjalankan Runnable setelah 2 detik (atau interval apa pun yang menurut Anda tepat), ketika timer menyala Anda menetapkan bendera yang menandai aplikasi sebagai latar belakang.
Dalam metode onResume () sebelum Anda membatalkan timer, Anda dapat menanyakan bendera latar belakang untuk melakukan operasi startup apa pun (mis. Memulai unduhan atau mengaktifkan layanan lokasi).
Solusi ini memungkinkan Anda untuk memiliki beberapa aktivitas di tumpukan belakang, dan tidak memerlukan izin apa pun untuk diterapkan.
Solusi ini berfungsi dengan baik jika Anda menggunakan bus acara juga, karena timer Anda dapat dengan mudah menyalakan sebuah acara dan berbagai bagian aplikasi Anda dapat merespons dengan sesuai.
Saya mulai berpikir ini adalah solusi terbaik (meski malang)
dhaag23
Yap ini adalah solusi terbaik yang pernah saya kelola juga. Saya harus menghentikan pemindaian bluetooth ketika aplikasi tidak memiliki latar depan, tetapi tidak bisa hanya menggunakan jeda atau berhenti atau menghancurkan karena saya tidak ingin terus-menerus berhenti dan mulai ketika pengguna menavigasi di sekitar aplikasi.
CaptRespect
3
Jika Anda mengaktifkan pengaturan pengembang "Don't keep actvities" - hanya memeriksa jumlah aktivitas yang dibuat tidak cukup. Anda harus memeriksa juga IsSaveInstanceState . Metode khusus saya adalahApplicationRunning () periksa apakah aplikasi Android sedang berjalan:
Saya tidak melihat bagaimana solusi ini dapat memberi saya jawaban atas pertanyaan sederhana dalam pernyataan IF tentang aktivitas saya (atau fragmen) apakah aplikasi saya ada di latar belakang atau di latar depan. Di mana pernyataan "JIKA" ???
ekashking
2
Untuk mendukung apa yang dikatakan CommonsWare dan Key, Anda mungkin dapat memperluas kelas Aplikasi dan meminta semua aktivitas Anda menyebutnya dengan metode onPause / onResume mereka. Ini memungkinkan Anda untuk mengetahui Aktivitas mana yang terlihat, tetapi ini mungkin dapat ditangani dengan lebih baik.
Bisakah Anda menguraikan apa yang ada dalam pikiran persisnya? Ketika Anda mengatakan menjalankan di latar belakang, maksud Anda hanya memiliki aplikasi Anda masih dalam memori meskipun saat ini tidak di layar? Sudahkah Anda memandang menggunakan Layanan sebagai cara yang lebih gigih untuk mengelola aplikasi Anda ketika tidak fokus?
Di android, kami memiliki pengaturan yang disebut "Data Latar Belakang". Pengaturan ini mengubah setiap koneksi data latar belakang saat aplikasi berjalan di latar belakang. Saya ingin menerapkan toggle "Data latar belakang" untuk aplikasi saya, jadi ketika tidak ada aktivitas saya yang terlihat oleh pengguna, saya ingin layanan saya berhenti melakukan transfer data apa pun, tetapi saat salah satu aktivitas saya berlanjut, saya ingin melanjutkan transfer data
cppdev
1
Applicationtidak memiliki onPause()atau onResume().
CommonsWare
1
@CommonsWare Anda benar, saya merujuk pada setiap Aktivitas individu yang menghubungi Aplikasi pada jeda / resume mereka. Ini pada dasarnya adalah ide yang baru saja Anda bagikan pada komentar untuk jawaban Anda, meskipun Anda menggunakan Layanan yang saya bayangkan adalah langkah yang lebih cerdas.
Dan
2
Saya melakukan implementasi ActivityLifecycleCallbacks saya sendiri. Saya menggunakan SherlockActivity, tetapi untuk kelas Activity normal mungkin bekerja.
Pertama, saya membuat antarmuka yang memiliki semua metode untuk melacak siklus aktivitas:
Aktivitas dijeda ketika Dialog muncul di atasnya sehingga semua solusi yang disarankan adalah setengah solusi. Anda perlu membuat kait untuk dialog juga.
Sistem membedakan antara aplikasi latar depan dan latar belakang. (Definisi latar belakang untuk tujuan pembatasan layanan berbeda dari definisi yang digunakan oleh manajemen memori; aplikasi mungkin di latar belakang berkaitan dengan manajemen memori , tetapi di latar depan berkaitan dengan kemampuannya untuk meluncurkan layanan.) Aplikasi adalah dianggap sebagai latar depan jika salah satu dari yang berikut ini benar:
Ini memiliki aktivitas yang terlihat, apakah aktivitas dimulai atau dijeda.
Ini memiliki layanan latar depan.
Aplikasi latar depan lain terhubung ke aplikasi, baik dengan mengikat ke salah satu layanannya atau dengan menggunakan salah satu penyedia kontennya. Misalnya, aplikasi berada di latar depan jika aplikasi lain mengikat:
IME
Layanan wallpaper
Pendengar pemberitahuan
Layanan suara atau teks
Jika tidak ada kondisi yang benar, aplikasi dianggap berada di latar belakang.
Anda harus menggunakan preferensi bersama untuk menyimpan properti dan menindaklanjutinya menggunakan layanan yang mengikat dari aktivitas Anda. Jika Anda hanya menggunakan pengikatan, (yang tidak pernah menggunakan startService), maka layanan Anda hanya akan berjalan ketika Anda mengikatnya, (bind onResume dan unbind onPause) yang akan membuatnya hanya berjalan di foreground saja, dan jika Anda ingin mengerjakannya latar belakang Anda dapat menggunakan layanan start stop reguler.
Saya pikir pertanyaan ini harus lebih jelas. Kapan? Dimana? Apa situasi spesifik Anda yang ingin Anda ketahui jika aplikasi Anda ada di latar belakang?
Saya hanya memperkenalkan solusi saya dengan cara saya.
Saya menyelesaikan ini dengan menggunakan bidang "kepentingan" RunningAppProcessInfokelas dalam onStopmetode setiap aktivitas di aplikasi saya, yang dapat dengan mudah dicapai dengan menyediakan BaseActivitykegiatan lain untuk memperluas yang mengimplementasikan onStopmetode untuk memeriksa nilai "kepentingan". Ini kodenya:
Saya memiliki sekitar 10 aktivitas dalam aplikasi saya. Jadi saya ingin tahu apakah tidak ada yang terlihat oleh pengguna. Secara keseluruhan, saya ingin tahu apakah aplikasi saya secara keseluruhan berjalan di latar belakang
cppdev
Jadi, Anda melacak semua 10-ish. Atau, seperti yang disarankan CommonsWare, jelaskan apa yang Anda coba lakukan.
Kunci
3
Ini tidak benar. Aktivitas Anda terlihat sampai onStop; antara onPausedan onStopitu terlihat , tetapi tidak di latar depan .
jamaah
@nickgrim: apa yang tidak benar? Saya menyatakan bahwa suatu kegiatan tidak lagi terlihat setelah onStop()dipanggil, yang selaras dengan apa yang Anda tulis.
Kunci
@ Kunci: Anda awalnya berkata sampai onPausedipanggil: suntingan baru-baru ini telah mengoreksi Anda.
jamaah
0
Bagaimana dengan menggunakan getApplicationState (). IsInForeground ()?
Menurut pendapat saya, banyak jawaban memperkenalkan banyak kode dan membawa banyak kerumitan dan tidak terbaca.
Ketika orang bertanya pada SO bagaimana berkomunikasi antara a Servicedan a Activity, saya biasanya menyarankan untuk menggunakan LocalBroadcastManager .
Mengapa?
Nah, dengan mengutip dokumen:
Anda tahu bahwa data yang Anda siarkan tidak akan meninggalkan aplikasi Anda, jadi tidak perlu khawatir membocorkan data pribadi.
Tidak mungkin bagi aplikasi lain untuk mengirim siaran ini ke aplikasi Anda, jadi Anda tidak perlu khawatir memiliki celah keamanan yang dapat mereka eksploitasi.
Ini lebih efisien daripada mengirim siaran global melalui sistem.
Tidak ada dalam dokumen:
Itu tidak memerlukan perpustakaan eksternal
Kode minimal
Cepat untuk diimplementasikan dan dipahami
Tidak ada callback yang diimplementasikan sendiri kustom / pola ultra-singleton / intra-proses apa pun ...
Tidak ada referensi yang kuat pada Activity, Application, ...
Deskripsi
Jadi, Anda ingin memeriksa apakah ada yang Activityada di latar depan. Anda biasanya melakukannya di Service, atau di Applicationkelas Anda .
Ini berarti, Activityobjek Anda menjadi pengirim sinyal (saya aktif / tidak aktif). Anda Service, di sisi lain, menjadi Receiver.
Ada dua momen di mana AndaActivity memberi tahu Anda apakah itu terjadi di latar depan atau di latar belakang (ya hanya dua ... bukan 6).
Ketika Activitymasuk ke latar depan, onResume()metode ini dipicu (juga disebut setelah onCreate()).
Ketika Activitymasuk di belakang, onPause()disebut.
Ini adalah saat-saat di mana Anda Activityharus mengirim sinyal kepada Anda Serviceuntuk menggambarkan kondisinya.
Dalam kasus multiple Activity, ingatlah an Activitymasuk ke latar belakang pertama, lalu yang lain masuk ke latar depan.
The Service/ Applicationhanya akan terus mendengarkan sinyal tersebut dan bertindak sesuai.
Kode (TLDR)
Anda Serviceharus menerapkan a BroadcastReceiveruntuk mendengarkan sinyal.
this.localBroadcastReceiver =newBroadcastReceiver(){@Overridepublicvoid onReceive(Context context,Intent intent){// received data if Activity is on / off}}publicstaticfinalIntentFilter SIGNAL_FILTER =newIntentFilter("com.you.yourapp.MY_SIGNAL")
@Overrideprotectedvoid onDestroy(){// I'm dead, no need to listen to anything anymore.LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);}
Sekarang Anda Activityharus mengkomunikasikan keadaan mereka.
Di Activity::onResume()
Intent intent =newIntent();
intent.setAction(SomeActivity.SIGNAL_FILTER);// put ON boolean in intent LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
Di Activity::onPause()
Intent intent =newIntent();
intent.setAction(SomeActivity.SIGNAL_FILTER);// put OFF boolean in intent LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
Situasi yang sangat, sangat umum
Pengembang: Saya ingin mengirim data dari saya Servicedan memperbarui Activity. Bagaimana cara memeriksa apakah Activityada di latar depan?
Biasanya tidak perlu memeriksa apakah Activityada di latar depan atau tidak. Cukup kirim data melalui LocalBroadcastManagerdari Anda Service. Jika Activityaktif, maka akan merespons dan bertindak.
Untuk situasi yang sangat umum ini, yang Servicemenjadi pengirim, dan Activitymengimplementasikannya BroadcastReceiver.
Jadi, buat Receiverdi Activity. Daftarkan onResume()dan batalkan pendaftarannya onPause(). Tidak perlu menggunakan metode siklus hidup lainnya .
Tentukan Receiverperilaku dalam onReceive()(perbarui ListView, lakukan ini, lakukan itu, ...).
Dengan cara ini Activityakan mendengarkan hanya jika di latar depan dan tidak ada yang akan terjadi jika di belakang atau dihancurkan.
Dalam kasus multiple Activity, mana Activityyang aktif akan merespons (jika mereka juga mengimplementasikannya Receiver).
Jika semua ada di latar belakang, tidak ada yang akan merespons dan sinyal akan hilang begitu saja.
Kirim data dari Servicevia Intent(lihat kode di atas) dengan menentukan ID sinyal.
Kecuali untuk Dukungan Multi-Jendela . Ini mungkin rumit (silakan uji jika diperlukan) ...
fun isAppInForeground():Boolean{
val activityManager = getSystemService(Context.ACTIVITY_SERVICE)asActivityManager?:returnfalse
val appProcesses = activityManager.runningAppProcesses ?:returnfalse
val packageName = packageName
for(appProcess in appProcesses){if(appProcess.importance ==ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName == packageName){returntrue}}returnfalse}
Tidak ada satu pun jawaban yang cukup sesuai dengan kasus spesifik jika Anda tampaknya tahu jika suatu aktivitas spesifik ada di permukaan dan jika Anda seorang SDK tanpa akses langsung ke Aplikasi. Bagi saya, saya berada di utas latar belakang yang baru saja menerima pemberitahuan push untuk pesan obrolan baru dan hanya ingin menampilkan pemberitahuan sistem jika layar obrolan tidak ada di latar depan.
Menggunakan ActivityLifecycleCallbacksyang seperti yang direkomendasikan dalam jawaban lain saya telah membuat kelas util kecil yang menampung logika apakah MyActivityada di Foreground atau tidak.
classMyActivityMonitor(context:Context):Application.ActivityLifecycleCallbacks{privatevar isMyActivityInForeground =false
init {(context.applicationContext asApplication).registerActivityLifecycleCallbacks(this)}
fun isMyActivityForeground()= isMyActivityInForeground
override fun onActivityPaused(activity:Activity?){if(activity isMyActivity){
isMyActivityInForeground =false}}override fun onActivityResumed(activity:Activity?){if(activity isMyActivity){
isMyActivityInForeground =true}}
Dan membacanya di tempat lain saat dibutuhkan melalui,
// Show a Toast Notification if App is not visible (ie in background. Not running, etc) SharedPreferences sharedPrefs =PreferenceManager.getDefaultSharedPreferences(context);if(!sharedPrefs.getBoolean("visible",true)){...}
Mungkin tidak anggun, tetapi itu bekerja untuk saya ...
Mungkin sudah terlambat untuk menjawab tetapi jika seseorang datang berkunjung maka di sini adalah solusi yang saya sarankan, Alasan mengapa aplikasi ingin mengetahui keadaannya di latar belakang atau datang ke latar depan bisa banyak, beberapa di antaranya, 1. Untuk menampilkan bersulang dan pemberitahuan ketika pengguna berada di BG. 2.Untuk melakukan beberapa tugas untuk pertama kalinya pengguna berasal dari BG, seperti polling, menggambar ulang dll.
Solusi oleh Idolon dan yang lainnya menangani bagian pertama, tetapi tidak untuk bagian kedua. Jika ada beberapa aktivitas di aplikasi Anda, dan pengguna beralih di antara mereka, maka pada saat Anda berada di aktivitas kedua, bendera yang terlihat akan salah. Jadi tidak bisa digunakan secara deterministik.
Saya melakukan sesuatu yang disarankan oleh CommonsWare, "Jika Layanan menentukan bahwa tidak ada kegiatan yang terlihat, dan tetap seperti itu selama beberapa waktu , hentikan transfer data pada titik penghentian logis berikutnya."
Garis dalam huruf tebal adalah penting dan ini dapat digunakan untuk mencapai item kedua. Jadi apa yang saya lakukan adalah sekali saya mendapatkan onActivityPaused (), jangan mengubah yang terlihat menjadi false secara langsung, melainkan memiliki penghitung waktu 3 detik (yaitu maks bahwa aktivitas selanjutnya harus diluncurkan), dan jika tidak ada onActivityResumed ( ) panggil dalam 3 detik berikutnya, ubah terlihat menjadi salah. Demikian pula dalam onActivityResumed () jika ada timer maka saya membatalkannya. Singkatnya, yang terlihat menjadi isAppInBackground.
Saya ingin merekomendasikan Anda untuk menggunakan cara lain untuk melakukan ini.
Saya kira Anda ingin menampilkan layar mulai saat program dimulai, jika sudah berjalan di backend, jangan tampilkan.
Aplikasi Anda dapat terus menulis waktu saat ini ke file tertentu. Ketika aplikasi Anda mulai, periksa stempel waktu terakhir, jika current_time-last_time> rentang waktu yang Anda tentukan untuk menulis waktu terbaru, itu berarti aplikasi Anda dihentikan, baik dibunuh oleh sistem atau pengguna sendiri.
Jawaban:
Ada beberapa cara untuk mendeteksi apakah aplikasi Anda berjalan di latar belakang, tetapi hanya satu di antaranya yang benar-benar dapat diandalkan:
Solusi yang tepat (kredit pergi ke Dan , CommonsWare dan NeTeInStEiN )
Melacak visibilitas aplikasi Anda sendiri menggunakan
Activity.onPause
,Activity.onResume
metode. Simpan status "visibilitas" di beberapa kelas lain. Pilihan yang baik adalah implementasi Anda sendiri dariApplication
a atauService
(ada juga beberapa variasi dari solusi ini jika Anda ingin memeriksa visibilitas aktivitas dari layanan).Contoh
Terapkan
Application
kelas khusus (perhatikanisActivityVisible()
metode statis):Daftarkan kelas aplikasi Anda di
AndroidManifest.xml
:Tambahkan
onPause
danonResume
ke setiapActivity
proyek (Anda dapat membuat leluhur bersama untuk Aktivitas Anda jika Anda mau, tetapi jika aktivitas Anda sudah diperluas dariMapActivity
/ListActivity
dll. Anda masih perlu menulis yang berikut dengan tangan):Pembaruan
ActivityLifecycleCallbacks ditambahkan di API level 14 (Android 4.0). Anda dapat menggunakannya untuk melacak apakah aktivitas aplikasi Anda saat ini terlihat oleh pengguna. Lihat jawaban Cornstalks di bawah ini untuk detailnya.
Yang salah
saya dulu menyarankan solusi berikut:
Meskipun solusi ini mungkin berhasil (dan memang berfungsi sebagian besar waktu), saya sangat menyarankan untuk tidak menggunakannya. Dan inilah alasannya. Seperti yang ditulis oleh Dianne Hackborn :
Saya berharap saya telah membaca ini sebelum saya memposting jawaban di SO, tapi mudah-mudahan tidak terlambat untuk mengakui kesalahan saya.
Solusi yang salah lagi
Droid-Fu perpustakaan disebutkan dalam salah satu penggunaan jawaban
ActivityManager.getRunningTasks
untuk yangisApplicationBroughtToBackground
metode. Lihat komentar Dianne di atas dan jangan gunakan metode itu juga.sumber
OnStop
permintaan untukisActivityVisible
.JANGAN GUNAKAN JAWABAN INI
jawaban user1269737 adalah cara yang tepat (disetujui Google / Android) untuk melakukan ini . Baca jawaban mereka dan beri mereka +1.
Saya akan meninggalkan jawaban asli saya di sini demi anak cucu. Ini adalah yang terbaik yang tersedia kembali pada tahun 2012, tetapi sekarang Android memiliki dukungan yang tepat untuk ini.
Jawaban asli
Kuncinya adalah menggunakan
ActivityLifecycleCallbacks
(perhatikan bahwa ini membutuhkan Android API level 14 (Android 4.0)). Periksa apakah jumlah kegiatan yang dihentikan sama dengan jumlah kegiatan yang dimulai. Jika mereka sama, aplikasi Anda sedang di-background. Jika ada lebih banyak kegiatan yang dimulai, aplikasi Anda masih terlihat. Jika ada lebih banyak aktivitas yang dilanjutkan dari yang dijeda, aplikasi Anda tidak hanya terlihat, tetapi juga ada di latar depan. Ada 3 status utama yang dapat diikuti aktivitas Anda: terlihat dan di latar depan, terlihat tetapi tidak di latar depan, dan tidak terlihat dan tidak di latar depan (yaitu di latar belakang).Hal yang sangat menyenangkan tentang metode ini adalah tidak memiliki masalah asinkron
getRunningTasks()
, tetapi Anda juga tidak perlu memodifikasi setiapActivity
aplikasi Anda untuk mengatur / menghapus sesuatu dionResumed()
/onPaused()
. Ini hanya beberapa baris kode yang lengkap, dan berfungsi di seluruh aplikasi Anda. Plus, tidak ada izin funky yang diperlukan juga.MyLifecycleHandler.java:
MyApplication.java:
@Mewzer telah mengajukan beberapa pertanyaan bagus tentang metode ini yang ingin saya balas dalam jawaban ini untuk semua orang:
onStop()
tidak dipanggil dalam situasi memori rendah; apakah itu masalah di sini?Tidak. Dokumen untuk
onStop()
mengatakan:Kuncinya di sini adalah "menjaga proses aktivitas Anda berjalan ..." Jika situasi dengan memori rendah ini pernah tercapai, proses Anda sebenarnya terbunuh (bukan hanya aktivitas Anda). Ini berarti bahwa metode ini memeriksa latar belakang masih berlaku karena a) Anda tetap tidak dapat memeriksa latar belakang jika proses Anda mati, dan b) jika proses Anda mulai lagi (karena aktivitas baru dibuat), anggota variabel (apakah statis atau tidak) untuk
MyLifecycleHandler
akan diatur ulang ke0
.Apakah ini berfungsi untuk perubahan konfigurasi?
Secara default, tidak. Anda harus secara eksplisit mengatur
configChanges=orientation|screensize
(|
dengan apa pun yang Anda inginkan) dalam file manifes Anda dan menangani perubahan konfigurasi, atau aktivitas Anda akan dihancurkan dan diciptakan kembali. Jika Anda tidak menetapkan ini, metode aktivitas Anda akan disebut dalam urutan ini:onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
. Seperti yang Anda lihat, tidak ada tumpang tindih (biasanya, dua aktivitas tumpang tindih sangat singkat ketika beralih di antara keduanya, yang merupakan cara kerja metode deteksi latar ini). Untuk mengatasi ini, Anda harus mengatur di semua proyek saya karena itu tidak diinginkan untuk seluruh aktivitas saya untuk dihancurkan di rotate / ubah ukuran layar, jadi saya tidak pernah menemukan ini menjadi bermasalah. (terima kasih kepada dpimka karena menyegarkan ingatan saya tentang ini dan mengoreksi saya!)configChanges
agar aktivitas Anda tidak hancur. Untungnya, saya harus mengaturconfigChanges
Satu catatan:
Ketika saya mengatakan "latar belakang" di sini dalam jawaban ini, maksud saya "aplikasi Anda tidak lagi terlihat." Aktivitas Android dapat terlihat namun tidak di latar depan (misalnya, jika ada hamparan notifikasi transparan). Itu sebabnya saya memperbarui jawaban ini untuk mencerminkan hal itu.
Penting untuk mengetahui bahwa Android memiliki momen limbo yang aneh ketika berganti aktivitas di mana tidak ada yang ada di latar depan . Untuk alasan ini, jika Anda memeriksa apakah aplikasi Anda berada di latar depan saat beralih di antara berbagai aktivitas (dalam aplikasi yang sama), Anda akan diberitahu bahwa Anda tidak berada di latar depan (meskipun aplikasi Anda masih merupakan aplikasi yang aktif dan terlihat. ).
Anda dapat memeriksa apakah aplikasi Anda di latar depan di Anda
Activity
'sonPause()
metode setelahsuper.onPause()
. Hanya ingat keadaan limbo aneh yang baru saja saya bicarakan.Anda dapat memeriksa apakah aplikasi Anda terlihat (yaitu jika tidak di latar belakang) di Anda
Activity
'sonStop()
metode setelahsuper.onStop()
.sumber
onStop()
setelahsuper.onStop()
. Jangan periksa latar belakang dionPause()
.SOLUSI GOOGLE - bukan peretasan, seperti solusi sebelumnya. Gunakan ProcessLifecycleOwner
Kotlin:
Jawa:
di app.gradle
Anda dapat membaca lebih lanjut tentang komponen arsitektur terkait Siklus Hidup di sini - https://developer.android.com/topic/libraries/architecture/lifecycle
sumber
companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }
maka Anda bisa mendapatkan latar latar depan denganArchLifecycleApp.isForeground()
The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes.
, ini tidak berfungsi untukmultiple processes
aplikasi, adakah api yang bisa kita raih dengan elegan?Memulai pustaka dukungan versi 26 Anda dapat menggunakan ProcessLifecycleOwner , cukup tambahkan ke dependensi Anda seperti dijelaskan di sini , misalnya:
Dan kemudian kueri
ProcessLifecycleOwner
kapan saja Anda ingin status aplikasi, contoh:sumber
Sejak Android API 16 ada cara sederhana untuk memeriksa apakah aplikasi di latar depan. Mungkin tidak mudah, tetapi tidak ada metode di Android yang sangat mudah. Metode ini cukup baik untuk digunakan ketika layanan Anda menerima pembaruan dari server dan harus memutuskan apakah akan menampilkan pemberitahuan, atau tidak (karena jika UI adalah latar depan, pengguna akan melihat pembaruan tanpa pemberitahuan).
sumber
JobService
untuk mendeteksi bahwa layanan berjalan di latar belakang.Jawaban Idolon adalah rawan kesalahan dan jauh lebih rumit walaupun berulang di sini memeriksa aplikasi android di latar depan atau tidak?dan di sini Menentukan aplikasi latar depan saat ini dari tugas atau layanan latar belakang
Ada pendekatan yang jauh lebih sederhana:
Pada BaseActivity yang diperluas oleh semua Kegiatan:
Setiap kali Anda perlu memeriksa apakah ada aktivitas aplikasi Anda di latar depan, cukup periksa
isVisible()
;Untuk memahami pendekatan ini, periksa jawaban siklus hidup aktivitas berdampingan ini: Siklus hidup aktivitas berdampingan
sumber
Idolon's answer is error prone
- sayangnya saya harus setuju dengan Anda. Berdasarkan komentar Dianne Hackborn di Grup Google, saya telah memperbarui jawaban saya. Silakan periksa detailnya.onPause
,onStop
, maupunonResume
acara disebut. Jadi, apa yang Anda lakukan jika tidak ada acara yang dipecat ?!Saya mencoba solusi yang disarankan yang menggunakan Application.ActivityLifecycleCallbacks dan banyak lainnya, tetapi mereka tidak berfungsi seperti yang diharapkan. Berkat Sarge , saya datang dengan solusi yang cukup mudah dan langsung yang saya jelaskan di bawah ini.
Itu juga perbedaan utama antara
onStop()
danonPause()
yang tidak disebutkan dalam artikel yang saya baca.Jadi berdasarkan perilaku Siklus Hidup Kegiatan ini, Anda dapat menghitung berapa kali dilakukan
onStart()
danonPause()
dipanggil dalam program Anda. Perhatikan bahwa untuk setiapActivity
program Anda, Anda harus menggantionStart()
danonStop()
, untuk menambah / mengurangi variabel statis yang digunakan untuk menghitung. Di bawah ini adalah kode yang mengimplementasikan logika ini. Perhatikan bahwa saya menggunakan kelas yang diperluasApplication
, jadi jangan lupa untuk mendeklarasikan diManifest.xml
dalam tag Aplikasi:,android:name=".Utilities"
meskipun dapat diimplementasikan menggunakan kelas kustom yang sederhana juga.Sekarang pada setiap Kegiatan program kami, kami harus mengganti
onStart()
danonStop()
dan menambah / mengurangi seperti yang ditunjukkan di bawah ini:Dengan logika ini, ada 2 kemungkinan kasus:
stateCounter = 0
: Jumlah yang dihentikan sama dengan jumlah Aktivitas yang dimulai, yang berarti bahwa aplikasi sedang berjalan di latar belakang.stateCounter > 0
: Jumlah awal lebih besar dari jumlah berhenti, yang berarti bahwa aplikasi sedang berjalan di latar depan.Memperhatikan:
stateCounter < 0
akan berarti bahwa ada lebih banyak Kegiatan yang berhenti daripada dimulai, yang tidak mungkin. Jika Anda menemukan kasus ini, berarti Anda tidak menambah / mengurangi penghitung seperti yang seharusnya.Kamu siap untuk pergi. Anda harus memeriksa apakah aplikasi Anda berada di latar belakang dalamnya
onStop()
.sumber
if(Utilities.isApplicationOnBackground()) …
keUtilities
. Karena kalau tidak, hanya aktivitas tertentu yang akan bereaksi pada acara tersebut.Tidak mungkin, singkat dari Anda melacaknya sendiri, untuk menentukan apakah ada aktivitas Anda yang terlihat atau tidak. Mungkin Anda harus mempertimbangkan untuk mengajukan pertanyaan StackOverflow baru, menjelaskan apa yang ingin Anda capai dari pengalaman pengguna, jadi kami mungkin dapat memberikan Anda ide-ide implementasi alternatif.
sumber
Service
. Jika demikian, mintalah kegiatan Anda memberi tahu layanan tersebut ketika mereka muncul dan menghilang. JikaService
menentukan bahwa tidak ada kegiatan yang terlihat, dan tetap seperti itu selama beberapa waktu, hentikan transfer data pada titik penghentian logis berikutnya. Ya, ini akan memerlukan kode untuk setiap aktivitas Anda, tetapi saat ini, itu adalah AFAIK yang tidak dapat dihindari.MyActivityClass
mewarisi dariActivity
dan menerapkan metode siklus hidup, dan membuat semua aktivitas Anda mewarisi dariMyActivityClass
. Ini tidak akan bekerja untukPreferenceActivity
atauMapActivity
meskipun (lihat pertanyaan ini )Anda dapat menggunakan ComponentCallbacks2 untuk mendeteksi jika aplikasi di latar belakang. BTW panggilan balik ini hanya tersedia di API Level 14 (Ice Cream Sandwich) dan di atasnya.
Anda akan mendapatkan panggilan ke metode:
public abstract void onTrimMemory (int level)
jika levelnya
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
maka aplikasi di latar belakang.Anda dapat mengimplementasikan interface ini ke
activity
,service
, dllsumber
Membangun @Cornstalks menjawab untuk menyertakan beberapa fitur yang bermanfaat.
Fitur tambahan:
App.java
AppLifecycleHandler.java
sumber
Solusi terbaik yang saya miliki dengan menggunakan timer.
Anda telah memulai timer di onPause () dan membatalkan timer yang sama di onResume (), ada 1 instance dari Timer (biasanya didefinisikan dalam kelas Aplikasi). Timer itu sendiri diatur untuk menjalankan Runnable setelah 2 detik (atau interval apa pun yang menurut Anda tepat), ketika timer menyala Anda menetapkan bendera yang menandai aplikasi sebagai latar belakang.
Dalam metode onResume () sebelum Anda membatalkan timer, Anda dapat menanyakan bendera latar belakang untuk melakukan operasi startup apa pun (mis. Memulai unduhan atau mengaktifkan layanan lokasi).
Solusi ini memungkinkan Anda untuk memiliki beberapa aktivitas di tumpukan belakang, dan tidak memerlukan izin apa pun untuk diterapkan.
Solusi ini berfungsi dengan baik jika Anda menggunakan bus acara juga, karena timer Anda dapat dengan mudah menyalakan sebuah acara dan berbagai bagian aplikasi Anda dapat merespons dengan sesuai.
sumber
Jika Anda mengaktifkan pengaturan pengembang "Don't keep actvities" - hanya memeriksa jumlah aktivitas yang dibuat tidak cukup. Anda harus memeriksa juga IsSaveInstanceState . Metode khusus saya adalahApplicationRunning () periksa apakah aplikasi Android sedang berjalan:
Di sini kode pekerjaan saya:
sumber
Satu-satunya solusi yang benar:
MainActivity.java:
MyApp.java:
sumber
Untuk mendukung apa yang dikatakan CommonsWare dan Key, Anda mungkin dapat memperluas kelas Aplikasi dan meminta semua aktivitas Anda menyebutnya dengan metode onPause / onResume mereka. Ini memungkinkan Anda untuk mengetahui Aktivitas mana yang terlihat, tetapi ini mungkin dapat ditangani dengan lebih baik.
Bisakah Anda menguraikan apa yang ada dalam pikiran persisnya? Ketika Anda mengatakan menjalankan di latar belakang, maksud Anda hanya memiliki aplikasi Anda masih dalam memori meskipun saat ini tidak di layar? Sudahkah Anda memandang menggunakan Layanan sebagai cara yang lebih gigih untuk mengelola aplikasi Anda ketika tidak fokus?
sumber
Application
tidak memilikionPause()
atauonResume()
.Saya melakukan implementasi ActivityLifecycleCallbacks saya sendiri. Saya menggunakan SherlockActivity, tetapi untuk kelas Activity normal mungkin bekerja.
Pertama, saya membuat antarmuka yang memiliki semua metode untuk melacak siklus aktivitas:
Kedua, saya mengimplementasikan antarmuka ini di kelas Aplikasi saya:
Ketiga, saya membuat kelas yang diperluas dari SherlockActivity:
Keempat, semua kelas yang diperluas dari SherlockActivity, saya ganti untuk MySherlockActivity:
Sekarang, di logcat Anda akan melihat log yang diprogram dalam implementasi Antarmuka yang dibuat di MyApplication.
sumber
Aktivitas dijeda ketika Dialog muncul di atasnya sehingga semua solusi yang disarankan adalah setengah solusi. Anda perlu membuat kait untuk dialog juga.
sumber
Karena belum disebutkan, saya akan menyarankan para pembaca untuk menjelajahi ProcessLifecycleOwner yang tersedia melalui komponen Arsitektur Android
sumber
Dokumen resmi:
Sistem membedakan antara aplikasi latar depan dan latar belakang. (Definisi latar belakang untuk tujuan pembatasan layanan berbeda dari definisi yang digunakan oleh manajemen memori; aplikasi mungkin di latar belakang berkaitan dengan manajemen memori , tetapi di latar depan berkaitan dengan kemampuannya untuk meluncurkan layanan.) Aplikasi adalah dianggap sebagai latar depan jika salah satu dari yang berikut ini benar:
Jika tidak ada kondisi yang benar, aplikasi dianggap berada di latar belakang.
sumber
Solusi lain untuk pos lama ini (bagi mereka yang mungkin membantu):
sumber
Lihat komentar di fungsi onActivityDestroyed.
Bekerja dengan SDK target versi 14>:
sumber
Anda harus menggunakan preferensi bersama untuk menyimpan properti dan menindaklanjutinya menggunakan layanan yang mengikat dari aktivitas Anda. Jika Anda hanya menggunakan pengikatan, (yang tidak pernah menggunakan startService), maka layanan Anda hanya akan berjalan ketika Anda mengikatnya, (bind onResume dan unbind onPause) yang akan membuatnya hanya berjalan di foreground saja, dan jika Anda ingin mengerjakannya latar belakang Anda dapat menggunakan layanan start stop reguler.
sumber
Saya pikir pertanyaan ini harus lebih jelas. Kapan? Dimana? Apa situasi spesifik Anda yang ingin Anda ketahui jika aplikasi Anda ada di latar belakang?
Saya hanya memperkenalkan solusi saya dengan cara saya.
Saya menyelesaikan ini dengan menggunakan bidang "kepentingan"
RunningAppProcessInfo
kelas dalamonStop
metode setiap aktivitas di aplikasi saya, yang dapat dengan mudah dicapai dengan menyediakanBaseActivity
kegiatan lain untuk memperluas yang mengimplementasikanonStop
metode untuk memeriksa nilai "kepentingan". Ini kodenya:sumber
Saya sarankan membaca halaman ini: http://developer.android.com/reference/android/app/Activity.html
Singkatnya, aktivitas Anda tidak lagi terlihat setelah
onStop()
dipanggil.sumber
onStop
; antaraonPause
danonStop
itu terlihat , tetapi tidak di latar depan .onStop()
dipanggil, yang selaras dengan apa yang Anda tulis.onPause
dipanggil: suntingan baru-baru ini telah mengoreksi Anda.Bagaimana dengan menggunakan getApplicationState (). IsInForeground ()?
sumber
Menurut pendapat saya, banyak jawaban memperkenalkan banyak kode dan membawa banyak kerumitan dan tidak terbaca.
Ketika orang bertanya pada SO bagaimana berkomunikasi antara a
Service
dan aActivity
, saya biasanya menyarankan untuk menggunakan LocalBroadcastManager .Mengapa?
Nah, dengan mengutip dokumen:
Tidak ada dalam dokumen:
Activity
,Application
, ...Deskripsi
Jadi, Anda ingin memeriksa apakah ada yang
Activity
ada di latar depan. Anda biasanya melakukannya diService
, atau diApplication
kelas Anda .Ini berarti,
Activity
objek Anda menjadi pengirim sinyal (saya aktif / tidak aktif). AndaService
, di sisi lain, menjadiReceiver
.Ada dua momen di mana Anda
Activity
memberi tahu Anda apakah itu terjadi di latar depan atau di latar belakang (ya hanya dua ... bukan 6).Ketika
Activity
masuk ke latar depan,onResume()
metode ini dipicu (juga disebut setelahonCreate()
).Ketika
Activity
masuk di belakang,onPause()
disebut.Ini adalah saat-saat di mana Anda
Activity
harus mengirim sinyal kepada AndaService
untuk menggambarkan kondisinya.Dalam kasus multiple
Activity
, ingatlah anActivity
masuk ke latar belakang pertama, lalu yang lain masuk ke latar depan.Jadi situasinya adalah: *
The
Service
/Application
hanya akan terus mendengarkan sinyal tersebut dan bertindak sesuai.Kode (TLDR)
Anda
Service
harus menerapkan aBroadcastReceiver
untuk mendengarkan sinyal.Daftarkan
Receiver
diService::onCreate()
Batalkan registrasi
Service::onDestroy()
Sekarang Anda
Activity
harus mengkomunikasikan keadaan mereka.Di
Activity::onResume()
Di
Activity::onPause()
Situasi yang sangat, sangat umum
Biasanya tidak perlu memeriksa apakah
Activity
ada di latar depan atau tidak. Cukup kirim data melaluiLocalBroadcastManager
dari AndaService
. JikaActivity
aktif, maka akan merespons dan bertindak.Untuk situasi yang sangat umum ini, yang
Service
menjadi pengirim, danActivity
mengimplementasikannyaBroadcastReceiver
.Jadi, buat
Receiver
diActivity
. DaftarkanonResume()
dan batalkan pendaftarannyaonPause()
. Tidak perlu menggunakan metode siklus hidup lainnya .Tentukan
Receiver
perilaku dalamonReceive()
(perbarui ListView, lakukan ini, lakukan itu, ...).Dengan cara ini
Activity
akan mendengarkan hanya jika di latar depan dan tidak ada yang akan terjadi jika di belakang atau dihancurkan.Dalam kasus multiple
Activity
, manaActivity
yang aktif akan merespons (jika mereka juga mengimplementasikannyaReceiver
).Jika semua ada di latar belakang, tidak ada yang akan merespons dan sinyal akan hilang begitu saja.
Kirim data dari
Service
viaIntent
(lihat kode di atas) dengan menentukan ID sinyal.sumber
sumber
Tidak ada satu pun jawaban yang cukup sesuai dengan kasus spesifik jika Anda tampaknya tahu jika suatu aktivitas spesifik ada di permukaan dan jika Anda seorang SDK tanpa akses langsung ke Aplikasi. Bagi saya, saya berada di utas latar belakang yang baru saja menerima pemberitahuan push untuk pesan obrolan baru dan hanya ingin menampilkan pemberitahuan sistem jika layar obrolan tidak ada di latar depan.
Menggunakan
ActivityLifecycleCallbacks
yang seperti yang direkomendasikan dalam jawaban lain saya telah membuat kelas util kecil yang menampung logika apakahMyActivity
ada di Foreground atau tidak.}
sumber
Dalam kegiatan saya onResume dan onPause saya menulis boolean isVisible ke SharedPrefences.
Dan membacanya di tempat lain saat dibutuhkan melalui,
Mungkin tidak anggun, tetapi itu bekerja untuk saya ...
sumber
Mungkin sudah terlambat untuk menjawab tetapi jika seseorang datang berkunjung maka di sini adalah solusi yang saya sarankan, Alasan mengapa aplikasi ingin mengetahui keadaannya di latar belakang atau datang ke latar depan bisa banyak, beberapa di antaranya, 1. Untuk menampilkan bersulang dan pemberitahuan ketika pengguna berada di BG. 2.Untuk melakukan beberapa tugas untuk pertama kalinya pengguna berasal dari BG, seperti polling, menggambar ulang dll.
Solusi oleh Idolon dan yang lainnya menangani bagian pertama, tetapi tidak untuk bagian kedua. Jika ada beberapa aktivitas di aplikasi Anda, dan pengguna beralih di antara mereka, maka pada saat Anda berada di aktivitas kedua, bendera yang terlihat akan salah. Jadi tidak bisa digunakan secara deterministik.
Saya melakukan sesuatu yang disarankan oleh CommonsWare, "Jika Layanan menentukan bahwa tidak ada kegiatan yang terlihat, dan tetap seperti itu selama beberapa waktu , hentikan transfer data pada titik penghentian logis berikutnya."
Garis dalam huruf tebal adalah penting dan ini dapat digunakan untuk mencapai item kedua. Jadi apa yang saya lakukan adalah sekali saya mendapatkan onActivityPaused (), jangan mengubah yang terlihat menjadi false secara langsung, melainkan memiliki penghitung waktu 3 detik (yaitu maks bahwa aktivitas selanjutnya harus diluncurkan), dan jika tidak ada onActivityResumed ( ) panggil dalam 3 detik berikutnya, ubah terlihat menjadi salah. Demikian pula dalam onActivityResumed () jika ada timer maka saya membatalkannya. Singkatnya, yang terlihat menjadi isAppInBackground.
Maaf tidak dapat menyalin-tempel kode ...
sumber
Saya ingin merekomendasikan Anda untuk menggunakan cara lain untuk melakukan ini.
Saya kira Anda ingin menampilkan layar mulai saat program dimulai, jika sudah berjalan di backend, jangan tampilkan.
Aplikasi Anda dapat terus menulis waktu saat ini ke file tertentu. Ketika aplikasi Anda mulai, periksa stempel waktu terakhir, jika current_time-last_time> rentang waktu yang Anda tentukan untuk menulis waktu terbaru, itu berarti aplikasi Anda dihentikan, baik dibunuh oleh sistem atau pengguna sendiri.
sumber