Secara latar belakang, maksud saya tidak ada aktivitas aplikasi yang saat ini terlihat oleh pengguna?
Secara latar belakang, maksud saya tidak ada aktivitas aplikasi yang saat ini terlihat oleh pengguna?
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 dari Application
a atau Service
(ada juga beberapa variasi dari solusi ini jika Anda ingin memeriksa visibilitas aktivitas dari layanan).
Contoh
Terapkan Application
kelas khusus (perhatikan isActivityVisible()
metode statis):
public class MyApplication extends Application {
public static boolean isActivityVisible() {
return activityVisible;
}
public static void activityResumed() {
activityVisible = true;
}
public static void activityPaused() {
activityVisible = false;
}
private static boolean activityVisible;
}
Daftarkan kelas aplikasi Anda di AndroidManifest.xml
:
<application
android:name="your.app.package.MyApplication"
android:icon="@drawable/icon"
android:label="@string/app_name" >
Tambahkan onPause
dan onResume
ke setiap Activity
proyek (Anda dapat membuat leluhur bersama untuk Aktivitas Anda jika Anda mau, tetapi jika aktivitas Anda sudah diperluas dari MapActivity
/ ListActivity
dll. Anda masih perlu menulis yang berikut dengan tangan):
@Override
protected void onResume() {
super.onResume();
MyApplication.activityResumed();
}
@Override
protected void onPause() {
super.onPause();
MyApplication.activityPaused();
}
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 daftarRunningAppProcessInfo
catatan. Untuk menentukan apakah aplikasi Anda berada diRunningAppProcessInfo.importance
bidang cek latar depan untuk persamaanRunningAppProcessInfo.IMPORTANCE_FOREGROUND
sementaraRunningAppProcessInfo.processName
sama dengan nama paket aplikasi Anda.Juga jika Anda menelepon
ActivityManager.getRunningAppProcesses()
dari utas UI aplikasi Anda, itu akan menjadi pentingIMPORTANCE_FOREGROUND
untuk tugas Anda, tidak peduli apakah itu benar-benar di latar depan atau tidak. Sebut saja di utas latar belakang (misalnya viaAsyncTask
) 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.getRunningTasks
untuk yang isApplicationBroughtToBackground
metode. Lihat komentar Dianne di atas dan jangan gunakan metode itu juga.
OnStop
permintaan untuk isActivityVisible
.
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.
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 Activity
aplikasi 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:
public class MyLifecycleHandler implements ActivityLifecycleCallbacks {
// 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.
private int resumed;
private int paused;
private int started;
private int stopped;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
}
@Override
public void onActivityPaused(Activity activity) {
++paused;
android.util.Log.w("test", "application is in foreground: " + (resumed > paused));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
}
@Override
public void 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" ...
public class MyApplication extends Application {
@Override
public void 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(new MyLifecycleHandler());
}
}
@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 MyLifecycleHandler
akan 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 setelah super.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 setelah super.onStop()
.
onStop()
setelah super.onStop()
. Jangan periksa latar belakang di onPause()
.
SOLUSI GOOGLE - bukan peretasan, seperti solusi sebelumnya. Gunakan ProcessLifecycleOwner
Kotlin:
class ArchLifecycleApp : 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:
public class ArchLifecycleApp extends Application implements LifecycleObserver {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppBackgrounded() {
//App in background
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void 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' }
}
}
Anda dapat membaca lebih lanjut tentang komponen arsitektur terkait Siklus Hidup di sini - https://developer.android.com/topic/libraries/architecture/lifecycle
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 untuk multiple 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:
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 ProcessLifecycleOwner
kapan saja Anda ingin status aplikasi, contoh:
//Check if app is in background
ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED;
//Check if app is in foreground
ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
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).
RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
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:
protected static boolean isVisible = false;
@Override
public void onResume()
{
super.onResume();
setVisible(true);
}
@Override
public void onPause()
{
super.onPause();
setVisible(false);
}
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
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
, maupun onResume
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.
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 ActivityBonStart()
akan dipanggil sebelum ActivityAonStop()
.
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 setiap Activity
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.xml
dalam tag Aplikasi:, android:name=".Utilities"
meskipun dapat diimplementasikan menggunakan kelas kustom yang sederhana juga.
public class Utilities extends Application
{
private static int stateCounter;
public void onCreate()
{
super.onCreate();
stateCounter = 0;
}
/**
* @return true if application is on background
* */
public static boolean isApplicationOnBackground()
{
return stateCounter == 0;
}
//to be called on each Activity onStart()
public static void activityStarted()
{
stateCounter++;
}
//to be called on each Activity onStop()
public static void activityStopped()
{
stateCounter--;
}
}
Sekarang pada setiap Kegiatan program kami, kami harus mengganti onStart()
dan onStop()
dan menambah / mengurangi seperti yang ditunjukkan di bawah ini:
@Override
public void onStart()
{
super.onStart();
Utilities.activityStarted();
}
@Override
public void 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()
.
if(Utilities.isApplicationOnBackground()) …
ke Utilities
. 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.
Service
. Jika demikian, mintalah kegiatan Anda memberi tahu layanan tersebut ketika mereka muncul dan menghilang. Jika Service
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 dari Activity
dan menerapkan metode siklus hidup, dan membuat semua aktivitas Anda mewarisi dari MyActivityClass
. Ini tidak akan bekerja untuk PreferenceActivity
atau MapActivity
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
, dll
public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 {
@Override
public void onConfigurationChanged(final Configuration newConfig) {
}
@Override
public void onLowMemory() {
}
@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// app is in background
}
}
}
Membangun @Cornstalks menjawab untuk menyertakan beberapa fitur yang bermanfaat.
Fitur tambahan:
App.java
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(AppLifecycleHandler.getInstance());
}
}
AppLifecycleHandler.java
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
private int resumed;
private int started;
private final String DebugName = "AppLifecycleHandler";
private boolean isVisible = false;
private boolean isInForeground = false;
private static AppLifecycleHandler instance;
public static AppLifecycleHandler getInstance() {
if (instance == null) {
instance = new AppLifecycleHandler();
}
return instance;
}
private AppLifecycleHandler() {
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
++resumed;
android.util.Log.w(DebugName, "onActivityResumed -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
setForeground((resumed > 0));
}
@Override
public void onActivityPaused(Activity activity) {
--resumed;
android.util.Log.w(DebugName, "onActivityPaused -> application is in foreground: " + (resumed > 0) + " (" + activity.getClass() + ")");
setForeground((resumed > 0));
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityStarted(Activity activity) {
++started;
android.util.Log.w(DebugName, "onActivityStarted -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
setVisible((started > 0));
}
@Override
public void onActivityStopped(Activity activity) {
--started;
android.util.Log.w(DebugName, "onActivityStopped -> application is visible: " + (started > 0) + " (" + activity.getClass() + ")");
setVisible((started > 0));
}
private void setVisible(boolean visible) {
if (isVisible == visible) {
// no change
return;
}
// visibility changed
isVisible = visible;
android.util.Log.w(DebugName, "App Visiblility Changed -> application is visible: " + isVisible);
// take some action on change of visibility
}
private void setForeground(boolean inForeground) {
if (isInForeground == inForeground) {
// no change
return;
}
// in foreground changed
isInForeground = inForeground;
android.util.Log.w(DebugName, "App In Foreground Changed -> application is in foreground: " + isInForeground);
// take some action on change of in foreground
}
public static boolean isApplicationVisible() {
return AppLifecycleHandler.getInstance().started > 0;
}
public static boolean isApplicationInForeground() {
return AppLifecycleHandler.getInstance().resumed > 0;
}
}
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.
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:
public class AppLifecycleService implements Application.ActivityLifecycleCallbacks {
private int created;
private boolean isSaveInstanceState;
private static AppLifecycleService instance;
private final static String TAG = AppLifecycleService.class.getName();
public static AppLifecycleService getInstance() {
if (instance == null) {
instance = new AppLifecycleService();
}
return instance;
}
public static boolean isApplicationRunning() {
boolean isApplicationRunning = true;
if (getCountCreatedActvities() == 0 && !isSaveInstanceState()) {
isApplicationRunning = false;
}
return isApplicationRunning;
}
public static boolean isSaveInstanceState() {
return AppLifecycleService.getInstance().isSaveInstanceState;
}
public static int getCountCreatedActvities() {
return AppLifecycleService.getInstance().created;
}
private AppLifecycleService() {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
this.isSaveInstanceState = true;
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
++created;
}
@Override
public void onActivityDestroyed(Activity activity) {
--created;
}
@Override
public void onActivityResumed(Activity activity) { }
@Override
public void onActivityPaused(Activity activity) { }
@Override
public void onActivityStarted(Activity activity) { }
@Override
public void onActivityStopped(Activity activity) { }
}
Satu-satunya solusi yang benar:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
MyApp.mainActivity = this;
super.onCreate(savedInstanceState);
...
}
public class MyApp extends Application implements LifecycleObserver {
public static MainActivity mainActivity = null;
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onAppBackgrounded() {
// app in background
if (mainActivity != null) {
...
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onAppForegrounded() {
// app in foreground
if (mainActivity != null) {
...
}
}
}
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?
Application
tidak memiliki onPause()
atau onResume()
.
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:
public interface ActivityLifecycleCallbacks{
public void onActivityStopped(Activity activity);
public void onActivityStarted(Activity activity);
public void onActivitySaveInstanceState(Activity activity, Bundle outState);
public void onActivityResumed(Activity activity);
public void onActivityPaused(Activity activity);
public void onActivityDestroyed(Activity activity);
public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}
Kedua, saya mengimplementasikan antarmuka ini di kelas Aplikasi saya:
public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
}
@Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
}
@Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
}
}
Ketiga, saya membuat kelas yang diperluas dari SherlockActivity:
public class MySherlockActivity extends SherlockActivity {
protected MyApplication nMyApplication;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
nMyApplication = (MyApplication) getApplication();
nMyApplication.onActivityCreated(this, savedInstanceState);
}
protected void onResume() {
// TODO Auto-generated method stub
nMyApplication.onActivityResumed(this);
super.onResume();
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
nMyApplication.onActivityPaused(this);
super.onPause();
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
nMyApplication.onActivityDestroyed(this);
super.onDestroy();
}
@Override
protected void onStart() {
nMyApplication.onActivityStarted(this);
super.onStart();
}
@Override
protected void onStop() {
nMyApplication.onActivityStopped(this);
super.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
nMyApplication.onActivitySaveInstanceState(this, outState);
super.onSaveInstanceState(outState);
}
}
Keempat, semua kelas yang diperluas dari SherlockActivity, saya ganti untuk MySherlockActivity:
public class MainActivity extends MySherlockActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Sekarang, di logcat Anda akan melihat log yang diprogram dalam implementasi Antarmuka yang dibuat di MyApplication.
Karena belum disebutkan, saya akan menyarankan para pembaca untuk menjelajahi ProcessLifecycleOwner yang tersedia melalui komponen Arsitektur Android
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.
Solusi lain untuk pos lama ini (bagi mereka yang mungkin membantu):
<application android:name=".BaseApplication" ... >
public class BaseApplication extends Application {
private class Status {
public boolean isVisible = true;
public boolean isFocused = true;
}
private Map<Activity, Status> activities;
@Override
public void onCreate() {
activities = new HashMap<Activity, Status>();
super.onCreate();
}
private boolean hasVisibleActivity() {
for (Status status : activities.values())
if (status.isVisible)
return true;
return false;
}
private boolean hasFocusedActivity() {
for (Status status : activities.values())
if (status.isFocused)
return true;
return false;
}
public void onActivityCreate(Activity activity, boolean isStarting) {
if (isStarting && activities.isEmpty())
onApplicationStart();
activities.put(activity, new Status());
}
public void onActivityStart(Activity activity) {
if (!hasVisibleActivity() && !hasFocusedActivity())
onApplicationForeground();
activities.get(activity).isVisible = true;
}
public void onActivityWindowFocusChanged(Activity activity, boolean hasFocus) {
activities.get(activity).isFocused = hasFocus;
}
public void onActivityStop(Activity activity, boolean isFinishing) {
activities.get(activity).isVisible = false;
if (!isFinishing && !hasVisibleActivity() && !hasFocusedActivity())
onApplicationBackground();
}
public void onActivityDestroy(Activity activity, boolean isFinishing) {
activities.remove(activity);
if(isFinishing && activities.isEmpty())
onApplicationStop();
}
private void onApplicationStart() {Log.i(null, "Start");}
private void onApplicationBackground() {Log.i(null, "Background");}
private void onApplicationForeground() {Log.i(null, "Foreground");}
private void onApplicationStop() {Log.i(null, "Stop");}
}
public class MyActivity extends BaseActivity {...}
public class BaseActivity extends Activity {
private BaseApplication application;
@Override
protected void onCreate(Bundle state) {
application = (BaseApplication) getApplication();
application.onActivityCreate(this, state == null);
super.onCreate(state);
}
@Override
protected void onStart() {
application.onActivityStart(this);
super.onStart();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
application.onActivityWindowFocusChanged(this, hasFocus);
super.onWindowFocusChanged(hasFocus);
}
@Override
protected void onStop() {
application.onActivityStop(this, isFinishing());
super.onStop();
}
@Override
protected void onDestroy() {
application.onActivityDestroy(this, isFinishing());
super.onDestroy();
}
}
Lihat komentar di fungsi onActivityDestroyed.
Bekerja dengan SDK target versi 14>:
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
public class AppLifecycleHandler implements Application.ActivityLifecycleCallbacks {
public static int active = 0;
@Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
active--;
}
@Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
active++;
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
@Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
active++;
}
@Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
active--;
}
@Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
active--;
// if active var here ever becomes zero, the app is closed or in background
if(active == 0){
...
}
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
active++;
}
}
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" RunningAppProcessInfo
kelas dalam onStop
metode setiap aktivitas di aplikasi saya, yang dapat dengan mudah dicapai dengan menyediakan BaseActivity
kegiatan lain untuk memperluas yang mengimplementasikan onStop
metode untuk memeriksa nilai "kepentingan". Ini kodenya:
public static boolean isAppRunning(Context context) {
ActivityManager activityManager = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appProcesses = activityManager
.getRunningAppProcesses();
for (RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.processName.equals(context.getPackageName())) {
if (appProcess.importance != RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE) {
return true;
}
}
}
return false;
}
Saya sarankan membaca halaman ini: http://developer.android.com/reference/android/app/Activity.html
Singkatnya, aktivitas Anda tidak lagi terlihat setelah onStop()
dipanggil.
onStop
; antara onPause
dan onStop
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.
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 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:
Activity
, Application
, ...Deskripsi
Jadi, Anda ingin memeriksa apakah ada yang Activity
ada di latar depan. Anda biasanya melakukannya di Service
, atau di Application
kelas Anda .
Ini berarti, Activity
objek 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 Activity
masuk ke latar depan, onResume()
metode ini dipicu (juga disebut setelah onCreate()
).
Ketika Activity
masuk di belakang, onPause()
disebut.
Ini adalah saat-saat di mana Anda Activity
harus mengirim sinyal kepada Anda Service
untuk menggambarkan kondisinya.
Dalam kasus multiple Activity
, ingatlah an Activity
masuk ke latar belakang pertama, lalu yang lain masuk ke latar depan.
Jadi situasinya adalah: *
Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON
The Service
/ Application
hanya akan terus mendengarkan sinyal tersebut dan bertindak sesuai.
Kode (TLDR)
Anda Service
harus menerapkan a BroadcastReceiver
untuk mendengarkan sinyal.
this.localBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// received data if Activity is on / off
}
}
public static final IntentFilter SIGNAL_FILTER = new IntentFilter("com.you.yourapp.MY_SIGNAL")
Daftarkan Receiver
diService::onCreate()
@Override
protected void onCreate() {
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}
Batalkan registrasi Service::onDestroy()
@Override
protected void onDestroy() {
// I'm dead, no need to listen to anything anymore.
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}
Sekarang Anda Activity
harus mengkomunikasikan keadaan mereka.
Di Activity::onResume()
Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
Di Activity::onPause()
Intent intent = new Intent();
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
Service
dan memperbaruiActivity
. Bagaimana cara memeriksa apakahActivity
ada di latar depan?
Biasanya tidak perlu memeriksa apakah Activity
ada di latar depan atau tidak. Cukup kirim data melalui LocalBroadcastManager
dari Anda Service
. Jika Activity
aktif, maka akan merespons dan bertindak.
Untuk situasi yang sangat umum ini, yang Service
menjadi pengirim, dan Activity
mengimplementasikannya BroadcastReceiver
.
Jadi, buat Receiver
di Activity
. Daftarkan onResume()
dan batalkan pendaftarannya onPause()
. Tidak perlu menggunakan metode siklus hidup lainnya .
Tentukan Receiver
perilaku dalam onReceive()
(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
, mana Activity
yang 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 Service
via Intent
(lihat kode di atas) dengan menentukan ID sinyal.
fun isAppInForeground(): Boolean {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager ?: return false
val appProcesses = activityManager.runningAppProcesses ?: return false
val packageName = packageName
for (appProcess in appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName == packageName) {
return true
}
}
return false
}
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 apakah MyActivity
ada di Foreground atau tidak.
class MyActivityMonitor(context: Context) : Application.ActivityLifecycleCallbacks {
private var isMyActivityInForeground = false
init {
(context.applicationContext as Application).registerActivityLifecycleCallbacks(this)
}
fun isMyActivityForeground() = isMyActivityInForeground
override fun onActivityPaused(activity: Activity?) {
if (activity is MyActivity) {
isMyActivityInForeground = false
}
}
override fun onActivityResumed(activity: Activity?) {
if (activity is MyActivity) {
isMyActivityInForeground = true
}
}
}
Dalam kegiatan saya onResume dan onPause saya menulis boolean isVisible ke SharedPrefences.
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
Editor editor = sharedPrefs.edit();
editor.putBoolean("visible", false);
editor.commit();
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.
Maaf tidak dapat menyalin-tempel kode ...
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.