Bir Android uygulamasının arka planda çalışıp çalışmadığını kontrol etme


329

Arka plana göre, uygulamanın faaliyetlerinin hiçbiri şu anda kullanıcı tarafından görülemiyor mu?



7
Burada kafam karıştı .. neden android bunun için uygulama sınıfında basit bir geçersiz kılma sağlayamıyor? Bunu platform düzeyinde bilmek çok mu zor? @Override korumalı geçersizlik onApplicationSentToBackground () {}
Chuck D

2
@ChuckD - Android SDK'nın zaman zaman yapmaktan kaçınmak istediği şey budur. : /
Mark


1
iOS'ta maça var, Google'ın bunu neden bu kadar zorlaştırdığından emin değil. Bu çok açık bir ihtiyaç.
Jerry Destremps

Yanıtlar:


388

Uygulamanızın arka planda çalışıp çalışmadığını tespit etmenin birkaç yolu vardır, ancak bunlardan yalnızca biri tamamen güvenilirdir:

  1. Doğru çözüm (kredi gidin Dan , CommonsWare ve NeTeInStEiN )
    kullanarak kendiniz uygulamanın Parça görünürlüğü Activity.onPause, Activity.onResumeyöntemleri. "Görünürlük" durumunu başka bir sınıfta saklayın. İyi seçimler, kendi uygulamanızdır Applicationveya hizmetten etkinlik görünürlüğünü kontrol etmek istiyorsanız bu çözümün birkaç varyasyonuService da vardır ). Örnek Özel sınıf uygulama ( statik yönteme dikkat edin ):
     

    ApplicationisActivityVisible()

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

    Uygulama sınıfınızı şu adrese kaydedin AndroidManifest.xml:

    <application
        android:name="your.app.package.MyApplication"
        android:icon="@drawable/icon"
        android:label="@string/app_name" >
    

    Ekle onPauseve onResumeher üzere Activityprojede (eğer isterseniz size Faaliyetleri için ortak bir atası oluşturabilir ancak etkinlik zaten uzanan eğer MapActivity/ ListActivityvs yine elle aşağıdaki yazmak gerekir):

    @Override
    protected void onResume() {
      super.onResume();
      MyApplication.activityResumed();
    }
    
    @Override
    protected void onPause() {
      super.onPause();
      MyApplication.activityPaused();
    }
    

     
    Güncelleme
    ActivityLifecycleCallbacks API seviye 14'te (Android 4.0) eklendi. Bunları uygulamanızın bir etkinliğinin şu anda kullanıcı tarafından görülebilir olup olmadığını izlemek için kullanabilirsiniz. Ayrıntılar için aşağıdaki Cornstalks cevabını kontrol edin.


  2. Aşağıdaki çözümü önermek için yanlış olanı kullandım:

    Kayıtların ActivityManager.getRunningAppProcesses()listesini döndüren geçerli ön plan / arka plan uygulamasını algılayabilirsiniz RunningAppProcessInfo. Başvurunuz ön plan onay üzerine olup olmadığını belirlemek için RunningAppProcessInfo.importanceiçin eşitlik alanında RunningAppProcessInfo.IMPORTANCE_FOREGROUNDise RunningAppProcessInfo.processNameis your uygulama paketi ismine eşittir.

    Ayrıca ActivityManager.getRunningAppProcesses()uygulama UI iş parçacığından ararsanız IMPORTANCE_FOREGROUND, aslında ön planda olsun ya da olmasın, göreviniz için önem dönecektir . Arka plan iş parçacığında (örneğin yoluyla AsyncTask) çağırın ve doğru sonuçları döndürecektir.

    Bu çözüm işe yarayabilir (ve çoğu zaman işe yarar) olsa da, kesinlikle kullanmaktan kaçınmanızı öneririm. İşte nedeni bu. Dianne Hackborn'un yazdığı gibi :

    Bu API'lar, uygulamaların UI akışlarını temel alması için değil, kullanıcıya çalışan uygulamaları veya bir görev yöneticisini veya benzerlerini göstermek gibi şeyler yapmak için vardır.

    Evet, bunlar için hafızada tutulan bir liste var. Bununla birlikte, başka bir işlemde kapalıdır, sizinkinden ayrı çalışan iş parçacıkları tarafından yönetilir ve (a) doğru kararı vermek için zamanında görmek veya (b) geri döndüğünüzde tutarlı bir resim elde etmek için güvenebileceğiniz bir şey değildir. Ayrıca "bir sonraki" etkinliğin ne olacağına dair karar her zaman anahtarın gerçekleşeceği noktada yapılır ve bu tam noktaya (aktivite durumunun anahtarı yapmak için kısa bir süre kilitlendiği yerde) kadar değildir. aslında bir sonraki şeyin ne olacağından emin olabilirsiniz.

    Ve buradaki uygulama ve küresel davranışın gelecekte aynı kalacağı garanti edilmemektedir.

    Keşke SO'ya bir cevap göndermeden önce bunu okumuş olsaydım, ama umarım hatamı kabul etmek için çok geç değildir.

  3. Bir başka yanlış çözüm
    Droid-Fu kütüphanesinde belirtilen cevaplardan biri yöntemi ActivityManager.getRunningTasksiçin kullanır isApplicationBroughtToBackground. Yukarıdaki Dianne'nin yorumuna bakın ve bu yöntemi de kullanmayın.


4
Ana ekran düğmesine bastığınızı veya başka bir uygulamanın odağı kazanıp kazanmadığını bilmek: 1) iyi çözümü uygulayın . 2) 'de OnStoptalep isActivityVisible.
Brais Gabin

28
Ne yazık ki 'doğru' çözümünüz benim için çalışmıyor. Uygulamanızdaki etkinlikler arasında geçiş yaptığınızı düşünün. O zaman ne olur 'inForeground' bayrağınız şu şekildedir: Doğru, Yanlış (1. etkinliğin onPause ile 2. etkinliğin onResume arasında) ve sonra tekrar Doğru, vb.
Radu

14
Tüm etkinlikleri doğrudan kontrol edemiyorsanız bu çözüm işe yaramaz. Örneğin, 3. taraf SDK'sından bir Etkinliğiniz varsa veya hatta bir ACTION_VIEW hedefi başlattıysanız.
user123321

66
Android çok korkutucu bir enkaz. Hiç kimse birisinin uygulama düzeyinde veriyi sürdürmek isteyebileceğini düşünmedi? Bana bir mola

8
Bu sorunun gerçek cevabı "Düzgün kontrol edemezsiniz" gibi görünüyor. Sözde 'doğru' çözüm en iyi çözümdür, bu nedenle ActivityLifecycleCallbacks kullanmaktır. Yine de "ön planda değil" olarak kaydedilecek etkinlikler arasında geçiş yapmayı düşünmelisiniz. Böyle basit bir şeyi kontrol edemeyeceğiniz aklıma geliyor ...
serin

263

BU CEVABI KULLANMAYIN

user1269737'nin cevabı bunu yapmanın uygun (Google / Android onaylı) yoludur . Cevaplarını okuyun ve onlara +1 verin.

Posterity aşkına orijinal cevabımı burada bırakacağım. Bu, 2012'de mevcut olan en iyisiydi, ancak şimdi Android bunun için uygun desteğe sahip.

Orijinal cevap

Anahtar kullanıyor ActivityLifecycleCallbacks(bunun Android API seviye 14 (Android 4.0) gerektirdiğini unutmayın). Sadece durdurulan faaliyet sayısının başlatılan faaliyet sayısına eşit olup olmadığını kontrol edin. Eşitlerse, uygulamanız arka plana alınıyor. Daha fazla başlatılan etkinlik varsa, başvurunuz hala görülebilir. Duraklatılmış etkinliklerden daha fazla devam ettirilirse, uygulamanız yalnızca görünür değil, aynı zamanda ön plandadır. Etkinliğinizin içinde olabileceği 3 ana durum vardır: görünür ve ön planda, görünür ancak ön planda değil, görünür ve ön planda değil (yani arka planda).

Bu yöntemle ilgili gerçekten güzel şey, asenkron sorunları olmamasıdır getRunningTasks()gelmez, ama aynı zamanda her değiştirmek gerekmez Activityset / unset şey için başvurunuza onResumed()/ ' onPaused(). Kendi kendine yeten birkaç kod satırı ve tüm uygulamanız boyunca çalışır. Ayrıca, funky izinleri de gerekmez.

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, herkes için bu yanıtta yanıtlamak istediğim bu yöntem hakkında bazı iyi sorular sordu:

onStop()düşük bellek durumlarında çağrılmaz; bu bir problem mi?

İçin dokümanlar sayılı onStop()söz hakkından:

Sistemin onPause () yöntemi çağrıldıktan sonra çalışmasını sürdürmek için yeterli belleğe sahip olmadığı düşük bellek durumlarında bu yöntemin hiçbir zaman çağrılamayabileceğini unutmayın.

Buradaki anahtar "etkinliğinizin işlemesini devam ettirmek ..." Bu düşük bellek durumuna ulaşıldığında işleminiz gerçekten öldürülür (yalnızca etkinliğiniz değil). Bu, arka planlılığı kontrol etme yönteminin hala geçerli olduğu anlamına gelir, çünkü a) işleminiz öldürülürse arka plan kontrol edemezsiniz ve b) işleminiz yeniden başlarsa (yeni bir etkinlik oluşturulduğu için), üye değişkenleri (statik olsun olmasın) MyLifecycleHandlersıfırlanacaktır 0.

Bu yapılandırma değişiklikleri için çalışıyor mu?

Varsayılan olarak hayır. Manifest dosyanızda açıkça configChanges=orientation|screensize( |istediğiniz başka bir şeyle) ayarlamanız ve yapılandırma değişikliklerini işlemeniz gerekir, aksi takdirde etkinliğiniz yok edilir ve yeniden oluşturulur. Bu set yoksa, sizin etkinliğin yöntemleri bu sırada adı verilecek: onCreate -> onStart -> onResume -> (now rotate) -> onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume. Gördüğünüz gibi, üst üste binme yok (normalde, ikisi arasında geçiş yaparken iki etkinlik çok kısa bir süre çakışıyor, bu da bu arka plan algılama yönteminin nasıl çalıştığı). Bu sorunu çözmek için configChanges, etkinliğinizin yok edilmeyeceği şekilde ayarlamanız gerekir . Neyse ki, ayarlamak zorunda kaldımconfigChangesTüm projelerimde zaten çünkü tüm aktivitemin ekran döndürme / yeniden boyutlandırmada yok edilmesi istenmeyen bir durumdu, bu yüzden bunu asla sorunlu bulmadım. (Bu konuda hafızamı yenilediğim ve düzelttiğim için dpimka'ya teşekkürler!)

Bir not:

Bu cevapta "arka plan" dediğimde, "uygulamanız artık görünür değil" demek istedim. Android etkinlikleri ön planda görünmese de görünebilir (örneğin, şeffaf bir bildirim yer paylaşımı varsa). Bu yüzden bu cevabı bunu yansıtacak şekilde güncelledim.

Android'in, hiçbir şeyin ön planda olmadığı etkinlikleri değiştirirken tuhaf bir limbo anı olduğunu bilmek önemlidir . Bu nedenle, etkinlikler arasında geçiş yaparken uygulamanızın ön planda olup olmadığını kontrol ederseniz (aynı uygulamada), uygulamanız ön planda olmadığınızı söyler (uygulamanız hala etkin uygulama ve görünür olsa bile) ).

Uygulamanız içinde ön planda olup olmadığını kontrol edebilirsiniz Activitybireyin onPause()yöntemle sonra super.onPause() . Az önce bahsettiğim garip limbo durumunu hatırla.

Uygulamanız görünür ise sizin de (arka planda değilse yani) kontrol edebilirsiniz Activitybireyin onStop()yöntemle sonra super.onStop() .


1
Bu ilginç görünüyor - ancak düşük bellek durumlarında ne olur? OnStop () işlevinin çağrılması garanti edilmez. Bir onStop () çağrılmadığı ve durdurulan sayacın artırılmadığı duruma girebilir miyiz - bu, arka plan kontrolünün artık güvenilir olmadığı anlamına gelir mi? Yoksa bu asla olmaz mı?
Mewzer

1
Ayrıca, bu yapılandırma değişikliklerini yoksayacak mı? Veya bir yapılandırma değişikliğinin sonucu olarak bir etkinlik yeniden oluşturulursa (örn. Yön değişikliğinde) uygulama arka plan olarak kabul edilir mi? Üzgünüm, sorular için ama bir şey üzerinde olduğunu düşünüyorum ve bu kenar durumlarda işe yarayıp yaramadığını bilmek istiyorum.
Mewzer

1
@Mewzer: Yorum olarak cevap verecektim, ancak bu cevapları almak biraz zaman alacak, bu yüzden birkaç dakika sonra tekrar kontrol edin ve cevabımı düzenleyeceğim.
Cornstalks

1
@Mewzer: Yanıtlarınızı şimdi bulmalısınız. Başka sorunuz varsa bize bildirin!
Cornstalks

2
@Mewzer: Sadece ilgilenen olabileceği not ekledi Özellikle, içinde artalanlamaya kontrol edin. onStop()Sonra super.onStop(). Arka planda olup olmadığını kontrol etmeyin onPause().
Cornstalks

187

GOOGLE SOLUTION - önceki çözümler gibi bir saldırı değil. ProcessLifecycleOwner Kotlin'i kullanın

:

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
    }

}


Java:

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

app.gradle içinde

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

Yaşam Döngüsü ile ilgili mimari bileşenler hakkında daha fazla bilgiyi buradan edinebilirsiniz - https://developer.android.com/topic/libraries/architecture/lifecycle


10
Bu kesinlikle doğru cevap olmalı! Bir cazibe gibi çalıştı: D
JaviOverflow

2
Bu Dışarıda bu sınıf daha kolay ön plan / arka plan durumuna erişmek yapsın diye de biraz değiştirilmiş, mükemmel çalışıyor companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }o zaman ile ön plan durumunu alabilirsinizArchLifecycleApp.isForeground()
Jose Jet

2
Ah adamım, bu eski cevabımdan çok daha iyi. Benden +1 kazan. Cevabımı, sizinkileri size yönlendirmek için güncelledim.
Cornstalks

2
Bu doğru bir yanıt olmasına rağmen, geri çağrıları uygulamaya gerek yoktur, sadece ProcessLifecycleOwner'ı istediğiniz zaman sorgulayabilirsiniz. Kontrol stackoverflow.com/a/52678290/6600000
Keivan Esbati

2
Doc'un dediği gibi The LifecycleOwner for the whole application process. Note that if your application has multiple processes, this provider does not know about other processes. , bu multiple processesuygulamalar için çalışmıyor , zarifçe elde edebileceğimiz bazı API'ler var mı?
acntwww

23

Destek kitaplığı sürüm 26'dan başlayarak ProcessLifecycleOwner'ı kullanabilirsiniz , sadece burada açıklandığı gibi bağımlılığınıza ekleyin , örneğin:

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
}

Ve sonra sadece ProcessLifecycleOwneruygulama durumu için istediğiniz zaman sorgulayın , örnekler:

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

2
Teşekkürler dostum, bu özellikle fcm kullanırken kodunuzun herhangi bir bölümünde uygun olan en iyi ve en kolay yoldur.
Mihae Kheel

uygulama tamamen kapatılırsa ilk yöntem ne döndürür?
Evgeniy Mishustin

@EvgeniyMishustin uygulamanın geçerli durumuna bağlıdır, ancak genellikle önce CREATED sonra DESTROYED görürsünüz ve bundan sonra yeni bir olay almazsınız.
Keivan Esbati

Peki IF uygulaması arka planda (ön planda) görmek için herhangi bir "IF" deyimi nerede ???
ekashking

@ekashking ifadenin tamamını if-yan tümcesine koydu. Örneğin: if (ProcessLifecycleOwner.get (). GetLifecycle (). GetCurrentState (). İsAtLeast (Lifecycle.State.STARTED)) => Uygulama ön planda ise
Keivan Esbati

20

Android API 16'dan beri uygulamanın ön planda olup olmadığını kontrol etmenin basit bir yolu var. Kusursuz olmayabilir, ancak Android'de hiçbir yöntem kusursuz değildir. Bu yöntem, hizmetiniz sunucudan güncelleme aldığında ve bildirim gösterip göstermeyeceğine karar vermesi gerektiğinde kullanmak için yeterlidir (çünkü kullanıcı arayüzü ön plandaysa, kullanıcı güncelleme yapmadan bildirimde bulunacaktır).

RunningAppProcessInfo myProcess = new RunningAppProcessInfo();
ActivityManager.getMyMemoryState(myProcess);
isInBackground = myProcess.importance != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;

Bu kod Hizmet sınıfı veya başka bir sınıf içinde olmalıdır, örneğin Uygulama sınıfı? Çok teşekkürler.
Woppi

..son satırı olarak kullanmak istediğiniz her yerde kontrol edeceğiniz bir boolean.
AO_

Bu, push bildirimleri için AWS Android SDK ile aynı yöntemdir.
17:38

"Hizmet sınırlamaları amacıyla arka plan tanımı, bellek yönetimi tarafından kullanılan tanımdan farklıdır; bir uygulama, bellek yönetimiyle ilgili olarak arka planda olabilir, ancak hizmetleri başlatma yeteneğiyle ilgili olarak ön planda olabilir.) " developer.android.com/about/versions/oreo/background.html (
ARLabs

Teşekkür ederim, bu işe yaradı! Ben JobServicehizmetin arka planda çalıştığını tespit etmek için bu kodu kullanabilirsiniz .
Michael Osofsky

17

Idolon'un yanıtı hata eğilimli ve çok daha karmaşık althought tekrar burada android uygulama ön planda olup olmadığını kontrol? ve burada Geçerli ön plan uygulamasını bir arka plan görevinden veya hizmetten belirleme

Çok daha basit bir yaklaşım var:

Bir Açık BaseActivity Faaliyetler uzatmak olduğunu:

protected static boolean isVisible = false;

 @Override
 public void onResume()
 {
     super.onResume();
     setVisible(true);
 }


 @Override
 public void onPause()
 {
     super.onPause();
     setVisible(false);
 }

Uygulama faaliyetlerinizden herhangi birinin ön planda olup olmadığını kontrol etmeniz gerektiğinde kontrol etmeniz yeterlidir isVisible();

Bu yaklaşımı anlamak için yan yana etkinlik yaşam döngüsünün bu cevabını kontrol edin: Etkinlik yan yana yaşam döngüsü


3
Idolon's answer is error prone- ne yazık ki seninle aynı fikirdeyim. Dianne Hackborn'un Google Grupları'ndaki yorumuna dayanarak cevabımı güncelledim. Ayrıntılar için lütfen kontrol edin.
Idolon

2
Bu da kusursuz bir çözüm değildir . Bir senaryo Kullanıcı daha sonra, bildirim panelini aşağı çekti eğer ne onPause, onStopne de onResumeolay denir. Peki bu olaylardan hiçbiri başlatılmazsa ne yaparsınız ?!


Maalesef, ekran kapalıyken bir etkinlik başlatıldığında bu kod yanlış çalışıyor. Bu durumda onResume ve onPause isVisible = false olarak adlandırılır.
CoolMind

@CoolMind Arka planda iken bir etkinlik başlatmak istediğiniz kullanım durumunu açıklar mısınız?
neteinstein

11

Application.ActivityLifecycleCallbacks ve diğerlerini kullanan önerilen çözümü denedim , ancak beklendiği gibi çalışmadılar. Sarge sayesinde aşağıda tarif ettiğim oldukça kolay ve anlaşılır bir çözüm buldum.

Bunlar çözümün anahtarı, ActivityA ve ActivityB, var ve biz ActivityA gelen ActivityB ararsanız (ve çağrı değil anlamanın gerçektir ActivityA.finish, ardından ActivityB en) onStart()adı verilecek önce ActivityA onStop().

Bu da arasındaki temel farktır onStop()ve onPause()okuduğum makalelerde bunlardan hiç bahsedilmemiştir.

Bu Faaliyetin Yaşam Döngüsü davranışına dayanarak, programınızda kaç kez çağrıldığını onStart()ve onPause()çağrıldığını sayabilirsiniz . O Not her biri için Activity programınızın, geçersiz kılmak gerekir onStart()ve onStop()sırayla, artma / statik değişken sayımı için kullanılan. Aşağıda bu mantığı uygulayan kod bulunmaktadır. Ben de genişleyen bir sınıf kullandığımı Applicationunutmayın, bu yüzden çok basit bir özel sınıf kullanılarak da uygulanabilmesine rağmen, Manifest.xmlUygulama etiketi içinde bildirmeyi unutmayın:.android:name=".Utilities"

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

Şimdi programımızın her Aktivite, biz geçersiz kılmak gerekir onStart()ve onStop()aşağıda gösterildiği gibi ve arttırma / azaltma:

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

Bu mantıkla 2 olası durum vardır:

  1. stateCounter = 0 : Durdurulan sayı, başlatılan Etkinliklerin sayısına eşittir; bu, uygulamanın arka planda çalıştığı anlamına gelir.
  2. stateCounter > 0 : Başlatma sayısı durma sayısından daha fazla, yani uygulama ön planda çalışıyor demektir.

Uyarı: stateCounter < 0başlamaktan ziyade durdurulmuş Faaliyetler olduğu anlamına gelir, bu imkansızdır. Bu durumla karşılaşırsanız, sayacı gerektiği gibi artırmaz / azaltmazsınız.

Gitmeye hazırsın. Uygulamanızın arka planda olup olmadığını kontrol etmek istersiniz onStop().


Ben hareket ediyorum if(Utilities.isApplicationOnBackground()) …için Utilities. Çünkü aksi takdirde sadece belirli bir etkinlik olaya tepki gösterecektir.
Görünen Ad

10

Faaliyetlerinizden herhangi birinin görünür olup olmadığını belirlemenin hiçbir yolu yoktur. Belki de bir kullanıcı deneyiminden ne elde etmeye çalıştığınızı açıklayan yeni bir StackOverflow sorusu sormayı düşünmelisiniz, böylece size alternatif uygulama fikirleri verebiliriz.


2
Android'de "Arka Plan Verileri" adlı bir ayarımız var. Bu ayar, uygulama arka planda çalışırken arka plan veri bağlantısını kapatır. Uygulamam için "Arka plan verileri" geçişini uygulamak istiyorum, bu nedenle etkinliklerimden hiçbiri kullanıcı tarafından görülemediğinde, hizmetimin herhangi bir veri aktarımı yapmayı durdurmasını istiyorum, ancak faaliyetlerim devam ettiğinde, veri aktarımına devam et
cppdev

1
@cppdev: Umarım, "veri aktarımı" a Service. Öyleyse, etkinliklerinizin göründükleri ve yok olduklarını bildirmelerini sağlayın. Eğer Servicehiçbir faaliyetler görünür olduğunu belirler ve bu zaman bir miktar süre böyle kalır sonraki mantıklı durma noktasında veri aktarımını durdurmak. Evet, bu, her bir faaliyetiniz için kod gerektirecektir, ancak şu anda bu kaçınılmaz AFAIK'dir.
CommonsWare

1
Ortak kodu tüm etkinlikleriniz arasında kopyalayıp yapıştırmaktan kaçınmak istiyorsanız , yaşam döngüsü yöntemlerini MyActivityClassdevralan Activityve uygulayan bir sınıf oluşturabilir ve tüm etkinliklerinizi devralmasını sağlayabilirsiniz MyActivityClass. Bu PreferenceActivityveya hiç işe yaramayacak MapActivity( bu soruya bakın )
Guillaume Brunerie

@CommonsWare etkin veya değil OnPause () OnResume () ile denemişti ama benim app görünüm ekranında etkin değilse ya da değil olup olmadığını kontrol arka planda çalışırsa
Manoj

@CommonsWare etkin ya da değil OnPause () OnResume () ile denemişti ama benim app görünüm ekranında etkin değilse ya da değil olup olmadığını kontrol arka planda çalışırsa
Manoj

5

Uygulamanın arka planda olup olmadığını tespit etmek için ComponentCallbacks2'yi kullanabilirsiniz . BTW bu geri arama yalnızca API Level 14 (Ice Cream Sandwich) ve üstü sürümlerde kullanılabilir.

Yönteme bir çağrı alacaksınız:

public abstract void onTrimMemory (int level)

seviye ise ComponentCallbacks2.TRIM_MEMORY_UI_HIDDENuygulama arka planda.

Bir bu arabirim uygulayabilen activity, servicevb

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

1
Cevabınızı denedim ama o kadar güvenilir değil. Ekran kilitliyken veya ekranı kilitlemek için "güç" düğmesine basıldığında onTrimMemory geri araması tetiklenmez. Uygulamanız görünürse ve durum çubuğu bildirimi yoluyla başka bir uygulama açarsanız da her zaman TRIM_MEMORY_UI_HIDDEN döndürmez. Tek güvenilir çözüm, ActivityLifecycleCallback'leri uygulamak ve bunları kullanım senaryosuna göre ayarlamaktır.
velval

4

@Cornstalks üzerine inşa etmek birkaç kullanışlı özellik içermek üzere cevap verir.

Ekstra özellikler:

  • Uygulamada herhangi bir yerde yapabilmeniz için singleton kalıbı tanıttı: AppLifecycleHandler.isApplicationVisible () ve AppLifecycleHandler.isApplicationInForeground ()
  • yinelenen etkinliklerin eklenmesi (yorumlara bakın // görünürlük değişikliği konusunda bazı işlemler yapın ve // ​​ön planda değişiklik yapılması konusunda bazı işlemler yapın)

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

3

Geldiğim en iyi çözüm zamanlayıcıları kullanıyor.

OnPause () öğesinde bir zamanlayıcı başlattınız ve onResume () öğesinde aynı zamanlayıcıyı iptal ettiniz, 1 Zamanlayıcı örneği var (genellikle Uygulama sınıfında tanımlanır). Zamanlayıcının kendisi, 2 saniye sonra (veya uygun olduğunu düşündüğünüz herhangi bir aralıktan sonra) Runnable'ı çalıştıracak şekilde ayarlanmıştır, zamanlayıcı tetiklendiğinde uygulamayı arka planda olarak işaretleyen bir bayrak ayarlarsınız.

Zamanlayıcıyı iptal etmeden önce onResume () yönteminde, herhangi bir başlatma işlemi gerçekleştirmek için arka plan bayrağını sorgulayabilirsiniz (örneğin indirmeleri başlat veya konum hizmetlerini etkinleştir).

Bu çözüm, arka yığın üzerinde çeşitli etkinliklere sahip olmanıza olanak tanır ve uygulanması için herhangi bir izin gerektirmez.

Zamanlayıcı bir olayı tetikleyebileceğinden ve uygulamanızın çeşitli bölümleri buna göre yanıt verebileceğinden, bir olay otobüsü de kullanıyorsanız bu çözüm iyi çalışır.


Bunun en iyi (talihsiz olsa da) bir çözüm olduğunu
düşünmeye başladım

Evet, bu benim de yönettiğim en iyi çözüm. Uygulama ön plana alınmadığında bluetooth taramasını durdurmam gerekiyordu, ancak kullanıcı uygulamada gezinirken sürekli durmak ve başlatmak istemediğim için sadece onpause veya stop veya destroy kullanamadım.
CaptRespect

3

"Etkinlikleri tutma" geliştirici ayarlarını açarsanız - yalnızca oluşturulan etkinliklerin sayısını kontrol etmek yeterli değildir. Ayrıca isSaveInstanceState öğesini de kontrol etmelisiniz . Benim özel yöntem isApplicationRunning () kontrolü android uygulaması çalışıyor:

İşte iş kodum:

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

}

3

Tek doğru çözüm:

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

}

Uygulamamın arka plan veya ön planda olup olmadığına bakılmaksızın, bu çözümün etkinliğim (veya parçam) üzerindeki bir IF ifadesinde basit bir soruya nasıl cevap verebileceğini görmüyorum. "EĞER" ifadesi nerede ???
ekashking

2

CommonsWare ve Key'in söylediklerine göz atmak için belki de Uygulama sınıfını genişletebilir ve tüm etkinliklerinizin onPause / onResume yöntemlerinde bunu çağırmasını sağlayabilirsiniz. Bu, hangi Faaliyetlerin görünür olduğunu bilmenizi sağlar, ancak bu muhtemelen daha iyi ele alınabilir.

Aklınızdakileri tam olarak anlatabilir misiniz? Arka planda çalıştığınızı söylediğinizde, şu anda ekranda olmasa bile uygulamanızın hala bellekte kalmasını mı kastediyorsunuz? Hizmetler'i, odakta değilken uygulamanızı yönetmenin daha kalıcı bir yolu olarak gördünüz mü?


Android'de "Arka Plan Verileri" adlı bir ayarımız var. Bu ayar, uygulama arka planda çalışırken arka plan veri bağlantısını kapatır. Uygulamam için "Arka plan verileri" geçişini uygulamak istiyorum, bu nedenle etkinliklerimden hiçbiri kullanıcı tarafından görülemediğinde, hizmetimin herhangi bir veri aktarımı yapmayı durdurmasını istiyorum, ancak etkinliklerimden biri devam ettiğinde, veri aktarımına devam et
cppdev 08

1
Applicationyok onPause()ya da onResume().
CommonsWare

1
@CommonsWare Haklısınız, duraklama / devam ettirme işlemiyle Uygulama ile iletişim kuran her bir Etkinliğe atıfta bulunuyordum. Bu, temelde cevabınızın yorumunda paylaştığınız fikirdir, ancak daha akıllı bir hareket olduğunu hayal ettiğim Hizmetleri kullandınız.
Dan

2

Kendi ActivityLifecycleCallbacks uygulamasını gerçekleştirdim. SherlockActivity kullanıyorum, ancak normal Activity sınıfı için işe yarayabilir.

İlk olarak, etkinlik yaşam döngüsünü izlemek için tüm yöntemlere sahip bir arabirim oluşturuyorum:

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

İkinci olarak, bu arayüzü Uygulamamın sınıfında uyguladım:

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

Üçüncü olarak, SherlockActivity'den uzanan bir sınıf oluşturuyorum:

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

Dördüncüsü, SherlockActivity'den uzanan tüm sınıf, MySherlockActivity için değiştirdim:

public class MainActivity extends MySherlockActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

}

Şimdi, logcat'te Uygulamamda yapılan Arayüz uygulamasında programlanan günlükleri göreceksiniz.


1

Bir İletişim Kutusu üzerine geldiğinde etkinlik duraklatılır, bu nedenle önerilen tüm çözümler yarı çözümlerdir. Diyaloglar için de kancalar oluşturmanız gerekir.



1

Resmi dokümanlar:

Sistem ön plan ve arka plan uygulamaları arasında ayrım yapar. (Hizmet sınırlamaları amacıyla arka planın tanımı, bellek yönetimi tarafından kullanılan tanımdan farklıdır; bir uygulama, bellek yönetimiyle ilgili olarak arka planda olabilir , ancak hizmetleri başlatma yeteneğiyle ilgili olarak ön planda olabilir.) Aşağıdakilerden herhangi biri doğruysa ön planda olduğu kabul edilir:

  1. Etkinliğin başlatılıp duraklatılmadığına bakılmaksızın görünür bir etkinliği vardır.
  2. Bir ön plan servisi vardır.
  3. Başka bir ön plan uygulaması, hizmetlerinden birine bağlanarak veya içerik sağlayıcılarından birini kullanarak uygulamaya bağlanır. Örneğin, başka bir uygulama kendi uygulamasına bağlanırsa uygulama ön plandadır:
    • IME
    • Duvar kağıdı hizmeti
    • Bildirim dinleyicisi
    • Ses veya metin hizmeti

Bu koşullardan hiçbiri doğru değilse, uygulama arka planda kabul edilir.


0

Bu eski yazı için başka bir çözüm (yardımcı olabilecek olanlar için):


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

}

0

OnActivityDestroyed işlevindeki açıklamaya bakın.

SDK hedef sürüm 14 ile çalışır>:

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

0

Mülkünüzü saklamak ve faaliyetlerinizdeki hizmet bağlayıcılığını kullanarak hareket etmek için paylaşılan bir tercih kullanmalısınız . Yalnızca ciltleme kullanırsanız (bu hiçbir zaman startService kullanmazsa), hizmetiniz yalnızca ona bağlandığınızda çalışır (yalnızca Resume üzerinde bağla ve onPause'a bağla) ve yalnızca ön planda çalışmasını ve üzerinde çalışmak istiyorsanız arka plan düzenli start stop servisini kullanabilirsiniz.


0

Bu sorunun daha açık olması gerektiğini düşünüyorum. Ne zaman? Nerede? Uygulamanız arka plandaysa, özel durumunuz nedir?

Çözümümü sadece kendi yoluma sokuyorum.
Bunu benim app RunningAppProcessInfoher faaliyetin onStopyönteminde sınıfın "önem" alanını kullanarak, basitçe "önem" değerini kontrol etmek için yöntemi BaseActivityuygular onStopyöntemini genişletmek için bir başka faaliyetler sağlayarak elde edilebilir elde olsun . İşte kod:

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

@ Idolon'un cevabında belirtildiği gibi bu önerilen bir çözüm değildir.
CoolMind

0

Bu sayfayı okumanızı tavsiye ederim: http://developer.android.com/reference/android/app/Activity.html

Kısacası, etkinliğiniz onStop()çağrıldıktan sonra artık görünmez .


3
Başvurumda yaklaşık 10 faaliyetim var. Bu yüzden bunların hiçbirinin kullanıcı tarafından görülüp görülmediğini bilmek istiyorum. Toplamda, bir bütün olarak uygulamamın arka planda çalışıp çalışmadığını bilmek istiyorum
cppdev

Böylece tüm 10-ish'i takip edersiniz. Veya CommonsWare'in önerdiği gibi, ne yapmaya çalıştığınızı açıklayın.
Anahtar

3
Bu doğru değil. Faaliyetiniz onStop; arasında onPauseve onStopbu kadar görünür değil, ön planda .
nickgrim

@ nickgrim: doğru olmayan ne? Bir etkinliğin onStop()çağrıldıktan sonra artık görünmediğini ve yazdıklarınızla aynı hizada olduğunu belirttim.
Anahtar

@Anahtar: Başlangıçta şu ana kadar arandınız: onPauseson bir düzenleme sizi düzeltti.
nickgrim

0

GetApplicationState (). İsInForeground () nasıl kullanılır?


0

Bence, birçok cevap ağır bir kod yükü getiriyor ve çok fazla karmaşıklık ve okunamayanlık getiriyor.

İnsanlar SO'ya a Serviceve a arasında nasıl iletişim kuracağını sorduğunda, Activitygenellikle LocalBroadcastManager'ı kullanmanızı öneririm .


Neden?

Belgeleri alıntılayarak:

  • Yayınladığınız verilerin uygulamanızdan ayrılmayacağını biliyorsunuz, bu nedenle özel verilerin sızdırılması konusunda endişelenmenize gerek yok.

  • Diğer uygulamaların bu yayınları uygulamanıza göndermesi mümkün değildir, bu nedenle yararlanabilecekleri güvenlik açıkları konusunda endişelenmenize gerek yoktur.

  • Sistem üzerinden küresel bir yayın göndermekten daha verimlidir.

Dokümanlar'da değil:

  • Harici kütüphaneler gerektirmez
  • Kod minimal
  • Uygulaması ve anlaşılması hızlı
  • Kendi kendine uygulanan geri aramalar / ultra-tekton / süreç içi desen yok ...
  • Hiçbir güçlü referanslar üzerinde Activity, Application...

Açıklama

Yani, Activityşu anda herhangi birinin ön planda olup olmadığını kontrol etmek istersiniz . Bunu genellikle a Serviceveya Applicationsınıfınızda yaparsınız .

Bu, Activitynesnelerinizin bir sinyalin göndericisi olduğu anlamına gelir (açık / kapalıyım). ServiceÖte yandan, senin olur Receiver.

Önünüzde mi yoksa arka planda mı olduğunu size söyleyen iki an vardır Activity(evet sadece iki ... 6 değil).

Ne zaman Activityön plana geçer, onResume()yöntem (ayrıca sonra adlandırılır tetiklenir onCreate()).

Ne zaman Activitygeriye gidecek onPause()denir.

Bunlar , durumunu tanımlamak Activityiçin sinyali size göndermeniz gereken anlardır Service.

Çoklu Activity'lerin olması durumunda, Activityönce a'nın arka plana gittiğini, sonra bir diğerinin ön plana geldiğini unutmayın.

Durum şu olurdu: *

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

Service/ ApplicationSadece bu sinyalleri dinlemeye devam ve buna göre hareket edecektir.


Kod (TLDR)

Sizin Servicebir uygulamalıdır BroadcastReceiversinyallerini dinlemek için.

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

Kayıt ReceiverinService::onCreate()

@Override
protected void onCreate() {
    LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(this.localBroadcastReceiver, SIGNAL_FILTER);
}

Kayıt defterini kaldırın Service::onDestroy()

@Override
protected void onDestroy() {
    // I'm dead, no need to listen to anything anymore.
    LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(this.localBroadcastReceiver);
}

Şimdi sizin Activitydurumunuzu bildirmelisiniz.

İçinde Activity::onResume()

Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put ON boolean in intent    
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);

İçinde Activity::onPause()

Intent intent = new Intent();
intent.setAction(SomeActivity.SIGNAL_FILTER); // put OFF boolean in intent    
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);

Çok, çok yaygın bir durum

Geliştirici: 'den veri göndermek Serviceve güncellemek istiyorum Activity. ActivityÖn planda olup olmadığını nasıl kontrol edebilirim ?

Genellikle Activityön planda olup olmadığını kontrol etmeye gerek yoktur . Sadece yoluyla veri göndermek LocalBroadcastManagerhesabınızla ilgili Service. Açıksa, Activityyanıt verir ve hareket eder.

Bu çok yaygın durum Serviceiçin gönderen olur ve Activityuygular BroadcastReceiver.

Yani, bir oluşturmak ReceiverGözlerinde farklı Activity. Kayıt olun onResume()ve kaydını kaldırın onPause(). Diğer yaşam döngüsü yöntemlerini kullanmaya gerek yoktur .

ReceiverDavranışı tanımlayın onReceive()(ListView'i güncelleyin, bunu yapın, yapın, ...).

Bu şekilde, Activitysadece ön plandaysa dinleyecek ve arkada ya da yok edildiğinde hiçbir şey olmayacak.

Çoklu Activity'lerin olması durumunda , hangisi Activityaçıksa (eğer de uygularsa Receiver) yanıt verecektir .

Eğer hepsi arka plandaysa, kimse cevap vermez ve sinyal kaybolur.

Sinyal kimliğini belirterek verileri Servicevia Intent(yukarıdaki koda bakın) gönderin .



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
}

0

Belirli bir etkinliğin ön planda olup olmadığını ve Uygulamaya doğrudan erişimi olmayan bir SDK olup olmadığınızı öğrenmek istiyorsanız, cevapların hiçbiri tam olarak bu duruma uymadı. Benim için yeni bir sohbet mesajı için bir push bildirimi aldım ve sadece sohbet ekranı ön planda değilse bir sistem bildirimi görüntülemek istiyorum arka plan iş parçacığı vardı.

ActivityLifecycleCallbacksBunu diğer cevaplarda önerildiği gibi kullanarak MyActivityÖn Plan'da olsun ya da olmasın mantığını barındıran küçük bir util sınıfı oluşturdum .

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

}


-1

OnResume ve onPause etkinliklerimde, SharedPrefences'a bir isVisible boole yazıyorum.

    SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
    Editor editor = sharedPrefs.edit();
    editor.putBoolean("visible", false);
    editor.commit();

Ve gerektiğinde başka bir yerde okuyun,

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

Belki zarif değil, ama benim için çalışıyor ...


-1

Cevaplamak için çok geç olabilir ama biri ziyarete gelirse o zaman burada önerdiğim çözüm, Bir uygulamanın arka planda olduğunu veya ön plana gelme durumunu bilmek istediği neden (ler), birkaç tane olabilir, 1. Kullanıcı BG'deyken tost ve bildirim göstermek için. 2.Kullanıcı anket, yeniden çizim vb.Gibi ilk kez BG'den gelen bazı görevleri gerçekleştirmek için.

Idolon ve diğerlerinin çözümü ilk kısmı halleder, ancak ikincisi için değildir. Uygulamanızda birden fazla etkinlik varsa ve kullanıcı bunlar arasında geçiş yapıyorsa, ikinci etkinliğe girdiğinizde görünür işaret yanlış olur. Dolayısıyla deterministik olarak kullanılamaz.

CommonsWare tarafından önerilen bir şey yaptım, "Hizmet görünür etkinlik olmadığını belirlerse ve bir süre bu şekilde kalırsa , bir sonraki mantıksal durma noktasında veri aktarımını durdurun."

Kalın harflerle yazılmış satır önemlidir ve bu ikinci öğeyi elde etmek için kullanılabilir. OnActivityPaused () aldıktan sonra yaptığım şey, görünür olanı doğrudan false olarak değiştirmeyin, bunun yerine 3 saniyelik bir zamanlayıcıya sahip olun (bir sonraki aktivitenin başlatılması gereken maksimum değerdir) ve onActivityResumed ( ) sonraki 3 saniye içinde arayın, görünür olarak false olarak değiştirin. Benzer şekilde onActivityResumed () içinde bir zamanlayıcı varsa iptal ederim. Özetle, görünür olan isAppInBackground olur.

Üzgünüz, kodu kopyalayıp yapıştıramıyor ...


-3

Bunu yapmak için başka bir yol kullanmanızı tavsiye ederim.

Sanırım program başlarken başlangıç ​​ekranını göstermek istiyorsunuz, eğer zaten arka uçta çalışıyorsa, gösterme.

Uygulamanız belirli bir dosyaya geçerli saati sürekli olarak yazabilir. Uygulamanız başlarken, son zaman damgasını kontrol edin, current_time-last_time> en son zamanı yazmak için belirttiğiniz zaman aralığı varsa, bu, sistem veya kullanıcının kendisi tarafından öldürülen başvurunuzun durdurulduğu anlamına gelir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.