Memeriksa apakah aplikasi Android sedang berjalan di latar belakang

329

Secara latar belakang, maksud saya tidak ada aktivitas aplikasi yang saat ini terlihat oleh pengguna?

cppdev
sumber
7
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. : /
Tandai
1
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:

  1. 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):

    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 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):

    @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.

  2. 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.

  3. 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.

Idola
sumber
4
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 ...
serine
263

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 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:

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 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 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() .

Batang jagung
sumber
1
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:

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

pengguna1269737
sumber
10
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 background
ProcessLifecycleOwner.get().getLifecycle().getCurrentState() == Lifecycle.State.CREATED;

//Check if app is in foreground
ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED);
Keivan Esbati
sumber
2
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).

RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
Juozas Kontvainis
sumber
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.
Michael Osofsky
17

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

neteinstein
sumber
3
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 ?!
Ini membawa saya ke pertanyaan ini: stackoverflow.com/questions/33657102/…
Ruchir Baronia
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 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.xmldalam 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:

  1. stateCounter = 0 : Jumlah yang dihentikan sama dengan jumlah Aktivitas yang dimulai, yang berarti bahwa aplikasi sedang berjalan di latar belakang.
  2. 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().

Menelaos Kotsollaris
sumber
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.

CommonsWare
sumber
2
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

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
     }
   }
}
Rohit Arya
sumber
1
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)

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;
    }
}
seb
sumber
3

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.

Andrew Kelly
sumber
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:

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

}
a_subscriber
sumber
3

Satu-satunya solusi yang benar:

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        MyApp.mainActivity = this;
        super.onCreate(savedInstanceState);
        ...
    }

MyApp.java:

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) {
            ...
        }
    }

}
Dmitry
sumber
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?

Dan
sumber
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:

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.

ClarkXP
sumber
1

Aktivitas dijeda ketika Dialog muncul di atasnya sehingga semua solusi yang disarankan adalah setengah solusi. Anda perlu membuat kait untuk dialog juga.

konmik
sumber
1

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:

  1. Ini memiliki aktivitas yang terlihat, apakah aktivitas dimulai atau dijeda.
  2. Ini memiliki layanan latar depan.
  3. 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.

Uddhav Gautam
sumber
0

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

}
alex
sumber
0

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++;
    }
}
ramden
sumber
0

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.

Ofek Ron
sumber
0

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:

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;
}
wxf04125
sumber
Ini bukan solusi yang disarankan sebagaimana dinyatakan dalam jawaban @ Idolon.
CoolMind
0

Saya sarankan membaca halaman ini: http://developer.android.com/reference/android/app/Activity.html

Singkatnya, aktivitas Anda tidak lagi terlihat setelah onStop()dipanggil.

Kunci
sumber
3
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 ()?

Jonathan
sumber
0

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.

Jadi situasinya adalah: *

Activity1 -- send --> Signal:OFF
Activity2 -- send --> Signal:ON

The Service/ Applicationhanya akan terus mendengarkan sinyal tersebut dan bertindak sesuai.


Kode (TLDR)

Anda Serviceharus menerapkan a BroadcastReceiveruntuk 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 ReceiverdiService::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 Activityharus 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 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.


Marko Pacak
sumber
0
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
}
ayoub laaziz
sumber
0

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.

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

}

scottyab
sumber
-1

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 ...

mtwagner
sumber
-1

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 ...

Sriram
sumber
-3

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.

pengguna2322866
sumber