Arka plana göre, uygulamanın faaliyetlerinin hiçbiri şu anda kullanıcı tarafından görülemiyor mu?
Arka plana göre, uygulamanın faaliyetlerinin hiçbiri şu anda kullanıcı tarafından görülemiyor mu?
Yanıtlar:
Uygulamanızın arka planda çalışıp çalışmadığını tespit etmenin birkaç yolu vardır, ancak bunlardan yalnızca biri tamamen güvenilirdir:
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.
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ılayabilirsinizRunningAppProcessInfo. Başvurunuz ön plan onay üzerine olup olmadığını belirlemek içinRunningAppProcessInfo.importanceiçin eşitlik alanındaRunningAppProcessInfo.IMPORTANCE_FOREGROUNDiseRunningAppProcessInfo.processNameis your uygulama paketi ismine eşittir.Ayrıca
ActivityManager.getRunningAppProcesses()uygulama UI iş parçacığından ararsanızIMPORTANCE_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 yoluylaAsyncTask) ç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.
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.
OnStoptalep isActivityVisible.
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.
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() .
onStop()Sonra super.onStop(). Arka planda olup olmadığını kontrol etmeyin onPause().
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
companion object { private var foreground = false fun isForeground() : Boolean { return foreground } }o zaman ile ön plan durumunu alabilirsinizArchLifecycleApp.isForeground()
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ı?
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);
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;
JobServicehizmetin arka planda çalıştığını tespit etmek için bu kodu kullanabilirsiniz .
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ü
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.
onPause, onStopne de onResumeolay denir. Peki bu olaylardan hiçbiri başlatılmazsa ne yaparsınız ?!
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 ActivityAonStop().
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:
stateCounter = 0 : Durdurulan sayı, başlatılan Etkinliklerin sayısına eşittir; bu, uygulamanın arka planda çalıştığı anlamına gelir.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().
if(Utilities.isApplicationOnBackground()) …için Utilities. Çünkü aksi takdirde sadece belirli bir etkinlik olaya tepki gösterecektir.
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.
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.
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 )
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
}
}
}
@Cornstalks üzerine inşa etmek birkaç kullanışlı özellik içermek üzere cevap verir.
Ekstra özellikler:
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;
}
}
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.
"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) { }
}
Tek doğru çözüm:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
MyApp.mainActivity = this;
super.onCreate(savedInstanceState);
...
}
public class MyApp extends Application implements LifecycleObserver {
public static MainActivity mainActivity = null;
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
void onAppBackgrounded() {
// app in background
if (mainActivity != null) {
...
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
void onAppForegrounded() {
// app in foreground
if (mainActivity != null) {
...
}
}
}
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ü?
Applicationyok onPause()ya da onResume().
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.
Daha önce bahsedilmediğinden, okuyuculara Android Architecture bileşenleri aracılığıyla kullanılabilen ProcessLifecycleOwner'ı keşfetmelerini önereceğim.
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:
Bu koşullardan hiçbiri doğru değilse, uygulama arka planda kabul edilir.
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();
}
}
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++;
}
}
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.
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;
}
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 .
onStop; arasında onPauseve onStopbu kadar görünür değil, ön planda .
onStop()çağrıldıktan sonra artık görünmediğini ve yazdıklarınızla aynı hizada olduğunu belirttim.
onPauseson bir düzenleme sizi düzeltti.
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:
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 istiyorumActivity.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 .
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
}
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
}
}
}
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 ...
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 ...
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.