Bir süre sonra ön plana getirildiğinde belirli bir şey yapan bir uygulama yazmaya çalışıyorum. Bir uygulamanın arka plana gönderildiğini veya ön plana getirildiğini tespit etmenin bir yolu var mı?
Bir süre sonra ön plana getirildiğinde belirli bir şey yapan bir uygulama yazmaya çalışıyorum. Bir uygulamanın arka plana gönderildiğini veya ön plana getirildiğini tespit etmenin bir yolu var mı?
Yanıtlar:
onPause()
Ve onResume()
uygulama tekrar arka plana ve ön plana getirildiğinde yöntemleri denir. Ancak, başvuru ilk kez başlatıldığında ve öldürülmeden önce de çağrılır. Etkinlik'te daha fazla bilgi bulabilirsiniz .
Orada arka plan veya ön planda iken uygulama durumunu almak için herhangi bir doğrudan bir yaklaşım değildir, ama gene de bu sorunla karşı karşıya ve birlikte çözüm bulduk onWindowFocusChanged
ve onStop
.
Daha fazla ayrıntı için Android'i kontrol edin : Bir Android uygulamasının arka plana gittiğini ve getRunningTasks veya getRunningAppProcesses olmadan ön plana döndüğünü tespit etme çözümü .
Mart 2018 GÜNCELLEME : Artık daha iyi bir çözüm var. Bkz. ProcessLifecycleOwner . Yeni mimari bileşenleri 1.1.0'ı kullanmanız gerekir (en son şu anda), ancak bunu yapmak için özel olarak tasarlanmıştır.
Bu cevapta verilen basit bir örnek var ama bunun için bir örnek uygulama ve bir blog yazısı yazdım .
Bunu 2014 yılında yazdığımdan beri farklı çözümler ortaya çıktı. Bazıları çalıştı, bazılarının çalıştığı düşünülüyordu , ancak kusurları vardı (benim dahil!) Ve biz, bir topluluk olarak (Android) sonuçlarla yaşamayı öğrendik ve özel durumlar için çözümler yazdık.
Asla tek bir kod snippet'inin aradığınız çözüm olduğunu varsaymayın, durum böyle değildir; daha da iyisi, ne yaptığını ve neden yaptığını anlamaya çalışın.
MemoryBoss
Sınıf aslında burada yazıldığı gibi benim tarafımdan hiç kullanılmamıştır, bu işin başına sözde kod sadece bir parça oldu.
Yeni mimari bileşenlerini kullanmamanız için geçerli bir neden olmadığı sürece (ve özellikle de süper eski API'leri hedefliyorsanız) bazıları varsa, devam edin ve bunları kullanın. Mükemmel olmaktan uzaklar, ama ikisi de değildi ComponentCallbacks2
.
GÜNCELLEME / NOTLAR (Kasım 2015) : İnsanlar iki yorum yapıyor, ilk önce >=
bunun yerine kullanılması gerekiyor, ==
çünkü belgeler kesin değerleri kontrol etmemeniz gerektiğini belirtiyor . Bu, çoğu durumda iyidir, ancak yalnızca uygulama arka plana gittiğinde bir şey yapmayı önemsiyorsanız , == kullanmanız ve ayrıca başka bir çözümle (Etkinlik Yaşam Döngüsü geri aramaları gibi) birleştirmeniz gerektiğini veya istediğiniz etkiyi elde edemeyebilirsiniz . Örnek (ve bu başıma) isterseniz olmasıdır kilidiarka plana gittiğinde uygulamanızı bir şifre ekranı ile (eğer aşina iseniz 1Password gibi), hafızanız azalırsa ve aniden test ediyorsanız uygulamanızı yanlışlıkla kilitleyebilirsiniz >= TRIM_MEMORY
, çünkü Android bir LOW MEMORY
aramayı tetikler ve sizinkinden daha yüksek. Bu yüzden nasıl / ne test ettiğine dikkat et.
Ayrıca, bazı insanlar geri döndüğünüzde nasıl tespit edeceğinizi sordular.
Aklıma gelen en basit yol aşağıda açıklanmıştır, ancak bazı insanlar buna aşina olmadığından, buraya bazı sahte kod ekliyorum. Var olduğunuzu YourApplication
ve MemoryBoss
sınıflarınız olduğunu varsayarsak , class BaseActivity extends Activity
(eğer yoksa bir tane oluşturmanız gerekir).
@Override
protected void onStart() {
super.onStart();
if (mApplication.wasInBackground()) {
// HERE YOU CALL THE CODE YOU WANT TO HAPPEN ONLY ONCE WHEN YOUR APP WAS RESUMED FROM BACKGROUND
mApplication.setWasInBackground(false);
}
}
Dialoglar bir etkinliği duraklatabileceği için onStart'ı öneriyorum, çünkü yaptığınız tek şey bir tam ekran iletişim kutusu görüntülüyse uygulamanızın "arka plana gittiğini" düşünmesini istemiyorsanız, ancak kilometreniz değişebilir.
Ve hepsi bu. İf bloğundaki kod yalnızca bir kez yürütülür , başka bir etkinliğe gitseniz bile, yeni olan (aynı zamanda extends BaseActivity
) raporlanır wasInBackground
, false
böylece çağrılana ve bayrak tekrar true değerine ayarlanana kadaronMemoryTrimmed
kodu yürütmez. .
Umarım yardımcı olur.
GÜNCELLEME / NOTLAR (Nisan 2015) : Bu koddaki tüm Kopyala ve Yapıştır'a gitmeden önce,% 100 güvenilir olmayabileceği ve en iyi sonuçları elde etmek için diğer yöntemlerle birleştirilmesi gereken birkaç örnek bulduğumu unutmayın . Özellikle, orada bilinen iki örneğionTrimMemory
çağrı geri yürütülecek garanti edilmemektedir:
Uygulamanız görünür durumdayken telefonunuz ekranı kilitlerse (cihazınızın nn dakika sonra kilitlendiğini söyleyin), kilit ekranı sadece üstte olduğu için bu geri arama çağrılmaz (veya her zaman değil), ancak uygulamanız hala kapalı olsa da "çalışır".
Cihazınızın belleği düşükse (ve bellek stresi altındaysa), İşletim Sistemi bu çağrıyı yok sayıyor ve doğrudan daha kritik seviyelere gidiyor gibi görünüyor.
Şimdi, uygulamanızın ne zaman arka plana gittiğini bilmenin sizin için ne kadar önemli olduğuna bağlı olarak, etkinlik yaşam döngüsünü ve neyin olmadığını takip ederek bu çözümü genişletmeniz gerekebilir veya gerekmeyebilir.
Yukarıdakileri aklınızda bulundurun ve iyi bir KG ekibine sahip olun;)
GÜNCELLEME SONU
Geç olabilir, ancak Ice Cream Sandwich (API 14) ve Üstü'nde güvenilir bir yöntem vardır .
Uygulamanız artık görünür kullanıcı arayüzü olmadığında, bir geri çağrının tetiklendiği ortaya çıkıyor. Özel bir sınıfta uygulayabileceğiniz geri aramaya ComponentCallbacks2 (evet, ikisiyle) denir . Bu geri arama yalnızca API Level 14 (Ice Cream Sandwich) ve üstü sürümlerde kullanılabilir.
Temel olarak yönteme bir çağrı alırsınız:
public abstract void onTrimMemory (int level)
Seviye 20 veya daha spesifiktir
public static final int TRIM_MEMORY_UI_HIDDEN
Bunu test ediyorum ve her zaman işe yarıyor, çünkü seviye 20 sadece uygulamanız artık görünmediği için bazı kaynakları serbest bırakmak isteyebileceğiniz bir "öneri".
Resmi dokümanları alıntılamak için:
OnTrimMemory (int) düzeyi: işlem bir kullanıcı arabirimi gösteriyordu ve artık bunu yapmıyor. Belleğin daha iyi yönetilebilmesi için bu noktada UI ile büyük ayırmalar serbest bırakılmalıdır.
Tabii ki, olasılıklar diğer olası resmi belgeler (bkz sonsuzdur vb kullanılmadan durduğunda bazı koleksiyonları temizlemek, aslında belirli bir süre içinde kullanılmamış olan (tasfiye bellek söylediklerini yapmak bu uygulamalıdır daha fazla kritik seviyeler).
Ama ilginç olan şey, işletim sisteminin size söylediği: HEY, uygulamanız arka plana gitti!
İlk etapta tam olarak bilmek istediğiniz şey budur.
Ne zaman döndüğünüzü nasıl belirlersiniz?
Kolay Eh, bu kadar bir "BaseActivity" eminim olabilir bayrağa gerçeği olduğunu sen geri onResume () kullanın. Çünkü geri dönmeyeceğinizi söyleyeceğiniz tek zaman aslında yukarıdaki onTrimMemory
yönteme bir çağrı aldığınızdadır .
İşe yarıyor. Yanlış pozitifler elde edemezsiniz. Bir etkinlik devam ediyorsa,% 100 oranında geri döndünüz. Kullanıcı tekrar arkaya giderse, başka bir onTrimMemory()
çağrı alırsınız .
Etkinliklerinizi (veya daha iyisi, özel bir sınıfı) susturmanız gerekir.
Bunu her zaman alacağınızı garanti etmenin en kolay yolu, aşağıdaki gibi basit bir sınıf oluşturmaktır:
public class MemoryBoss 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) {
// We're in the Background
}
// you might as well implement some memory cleanup here and be a nice Android dev.
}
}
Bunu kullanmak için, Uygulama uygulamanızda ( bir tane var, SAĞ? ), Aşağıdakileri yapın :
MemoryBoss mMemoryBoss;
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
mMemoryBoss = new MemoryBoss();
registerComponentCallbacks(mMemoryBoss);
}
}
Bir oluşturursanız Interface
bir ekleyebilirsiniz else
buna if
ve uygulamak ComponentCallbacks
API 14. altındaki hiçbir kullanılan (2 olmadan) geri arama yalnızca var, diyeceksin onLowMemory()
yöntem ve arka planda giderken çağrılmadığı , ancak Döşeme belleğe kullanmalısınız .
Şimdi Uygulamanızı başlatın ve eve basın. Sizin onTrimMemory(final int level)
(: eklenti günlüğü ipucu) yöntemi çağrılmalıdır.
Son adım geri aramanın kaydını silmek. Muhtemelen en iyi yer onTerminate()
Uygulamanızın yöntemidir, ancak bu yöntem gerçek bir cihazda çağrılmaz:
/** * This method is for use in emulated process environments. It will * never be called on a production Android device, where processes are * removed by simply killing them; no user code (including this callback) * is executed when doing so. */
Dolayısıyla, artık kayıt olmak istemediğiniz bir durumunuz yoksa, işleminiz yine de işletim sistemi düzeyinde ölüyor olduğundan, güvenliği göz ardı edebilirsiniz.
Bir noktada kaydını silmeye karar verirseniz (örneğin, uygulamanızın temizlenmesi ve ölmesi için bir kapatma mekanizması sağlarsanız) şunları yapabilirsiniz:
unregisterComponentCallbacks(mMemoryBoss);
Ve bu kadar.
level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
güncellemenizde sorundan kaçınıyorum, nokta 2'yi kullanıyorum.
İşte bunu nasıl çözdüm. Etkinlik geçişleri arasında bir zaman referansı kullanmanın, büyük olasılıkla bir uygulamanın "arka planı" olup olmadığına dair yeterli kanıt sağlayacağı öncülünde çalışır.
İlk olarak, bir zamanlayıcı, TimerTask, bir aktiviteden diğerine geçişin makul olarak alabileceği maksimum milisaniye sayısını temsil eden bir sabite sahip bir android.app.Application örneği kullandım (buna Uygulamam diyelim) 2s değerine sahip) ve uygulamanın "arka planda" olup olmadığını belirtmek için bir boole değeri:
public class MyApplication extends Application {
private Timer mActivityTransitionTimer;
private TimerTask mActivityTransitionTimerTask;
public boolean wasInBackground;
private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;
...
Uygulama ayrıca zamanlayıcı / görevi başlatmak ve durdurmak için iki yöntem sağlar:
public void startActivityTransitionTimer() {
this.mActivityTransitionTimer = new Timer();
this.mActivityTransitionTimerTask = new TimerTask() {
public void run() {
MyApplication.this.wasInBackground = true;
}
};
this.mActivityTransitionTimer.schedule(mActivityTransitionTimerTask,
MAX_ACTIVITY_TRANSITION_TIME_MS);
}
public void stopActivityTransitionTimer() {
if (this.mActivityTransitionTimerTask != null) {
this.mActivityTransitionTimerTask.cancel();
}
if (this.mActivityTransitionTimer != null) {
this.mActivityTransitionTimer.cancel();
}
this.wasInBackground = false;
}
Bu çözümün son parçası, bu yöntemlerin her birine, tüm etkinliklerin onResume () ve onPause () olaylarından veya tercihen tüm somut Faaliyetlerinizin miras aldığı bir temel Faaliyete bir çağrı eklemektir:
@Override
public void onResume()
{
super.onResume();
MyApplication myApp = (MyApplication)this.getApplication();
if (myApp.wasInBackground)
{
//Do specific came-here-from-background code
}
myApp.stopActivityTransitionTimer();
}
@Override
public void onPause()
{
super.onPause();
((MyApplication)this.getApplication()).startActivityTransitionTimer();
}
Bu nedenle, kullanıcının uygulamanızın faaliyetleri arasında gezinmesi durumunda, çıkış yapan etkinliğin onPause () zamanlayıcısını başlatır, ancak girilen hemen hemen yeni etkinlik, maksimum geçiş süresine ulaşmadan önce zamanlayıcıyı iptal eder. Ve böylece wasInBackground olacağını yanlış .
Öte yandan, bir Aktivite Başlatıcı'dan ön plana geldiğinde, cihaz uyandırma, telefon görüşmesi bitirme vb., Bu olaydan önce çalıştırılan zamanlayıcı görevi büyük olasılıkla daha fazladır ve bu nedenle wasInBackground true olarak ayarlanmıştır .
Düzenleme: yeni mimari bileşenler umut verici bir şey getirdi: ProcessLifecycleOwner , bkz. @ Vokilam'ın cevabı
class YourApplication : Application() {
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(AppLifecycleTracker())
}
}
class AppLifecycleTracker : Application.ActivityLifecycleCallbacks {
private var numStarted = 0
override fun onActivityStarted(activity: Activity?) {
if (numStarted == 0) {
// app went to foreground
}
numStarted++
}
override fun onActivityStopped(activity: Activity?) {
numStarted--
if (numStarted == 0) {
// app went to background
}
}
}
Evet. Burada çok garip çözümlere sahip olduğumuz için bu basit çözümün işe yaradığına inanmanın zor olduğunu biliyorum.
Ama umut var.
ProcessLifecycleOwner
umut verici bir çözüm gibi görünüyor.
ProcessLifecycleOwner sevk edecek
ON_START
,ON_RESUME
bu olaylar üzerinden bir ilk etkinlik hamle olarak, olayları.ON_PAUSE
,,ON_STOP
etkinlikler son etkinliklerden geçtikten sonra bir gecikmeyle gönderilir . Bu gecikme,ProcessLifecycleOwner
bir yapılandırma değişikliği nedeniyle etkinlikler yok edilir ve yeniden oluşturulursa herhangi bir etkinlik göndermeyeceğini garanti edecek kadar uzundur .
Bir uygulama kadar basit olabilir
class AppLifecycleListener : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onMoveToForeground() { // app moved to foreground
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onMoveToBackground() { // app moved to background
}
}
// register observer
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleListener())
Kaynak koduna göre, mevcut gecikme değeri 700ms
.
Ayrıca bu özelliği kullanmak için şunlar gerekir dependencies
:
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
implementation "android.arch.lifecycle:extensions:1.0.0"
annotationProcessor "android.arch.lifecycle:compiler:1.0.0"
google()
Martín Marconcinis'in cevabına (teşekkürler!) Dayanarak sonunda güvenilir (ve çok basit) bir çözüm buldum.
public class ApplicationLifecycleHandler implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
private static final String TAG = ApplicationLifecycleHandler.class.getSimpleName();
private static boolean isInBackground = false;
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
if(isInBackground){
Log.d(TAG, "app went to foreground");
isInBackground = false;
}
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onConfigurationChanged(Configuration configuration) {
}
@Override
public void onLowMemory() {
}
@Override
public void onTrimMemory(int i) {
if(i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN){
Log.d(TAG, "app went to background");
isInBackground = true;
}
}
}
Daha sonra bunu Uygulama sınıfınızın onCreate () öğesine ekleyin
public class MyApp extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
registerActivityLifecycleCallbacks(handler);
registerComponentCallbacks(handler);
}
}
Bu yöntemi kullanıyoruz. Çalışmak için çok basit görünüyor, ama bizim app iyi test edildi ve aslında "ev" düğmesi, "dönüş" düğmesi veya ekran kilidi sonra ana ekrana gitmek de dahil olmak üzere her durumda şaşırtıcı derecede iyi çalışıyor. Bir şans ver.
Fikir, ön planda olduğunda, Android her zaman bir öncekini durdurmadan önce yeni etkinliklere başlar. Bu garanti edilmez, ama böyle çalışır. BTW, Flurry aynı mantığı kullanıyor gibi görünüyor (sadece bir tahmin, bunu kontrol etmedim, ama aynı olaylara kanca yapıyor).
public abstract class BaseActivity extends Activity {
private static int sessionDepth = 0;
@Override
protected void onStart() {
super.onStart();
sessionDepth++;
if(sessionDepth == 1){
//app came to foreground;
}
}
@Override
protected void onStop() {
super.onStop();
if (sessionDepth > 0)
sessionDepth--;
if (sessionDepth == 0) {
// app went to background
}
}
}
Düzenleme: yorumlara göre, kodun sonraki sürümlerinde onStart () öğesine de taşındık. Ayrıca, ilk yazımda eksik olan süper çağrılar ekliyorum, çünkü bu bir çalışma kodundan çok bir kavramdı.
onStop is called when the activity is no longer visible to the user
.
Uygulamanız bir sekme çubuğu widget'ı gibi birden fazla etkinlik ve / veya yığınlanmış etkinlik içeriyorsa, onPause () ve onResume () öğelerinin geçersiz kılınması çalışmaz. Yani yeni bir etkinlik başlatılırken, mevcut etkinlikler yeni etkinlik oluşturulmadan önce duraklatılır. Aynı şey bir etkinliği bitirirken ("geri" düğmesini kullanarak) uygulanır.
İstendiği gibi çalışan iki yöntem buldum.
Birincisi GET_TASKS iznini gerektirir ve paket adlarını karşılaştırarak cihazdaki en iyi çalışan etkinliğin uygulamaya ait olup olmadığını kontrol eden basit bir yöntemden oluşur:
private boolean isApplicationBroughtToBackground() {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}
Bu yöntem Droid-Fu (şimdi Ateşleme olarak adlandırılır) çerçevesinde bulundu.
Kendimi uyguladığım ikinci yöntem GET_TASKS iznini gerektirmiyor, ki bu iyi. Bunun yerine uygulanması biraz daha karmaşıktır.
MainApplication sınıfınızda uygulamanızda çalışan etkinliklerin sayısını izleyen bir değişkeniniz vardır. Her etkinlik için onResume () öğesinde değişkeni artırırsınız ve onPause () öğesinde onu azaltırsınız.
Çalışan etkinlik sayısı 0'a ulaştığında, aşağıdaki koşullar geçerli olursa uygulama arka plana alınır:
Uygulamanın arka plana istifa ettiğini tespit edebildiğinizde, ön plana geri getirildiğinde de kolayca tespit edilebilir.
Bir oluşturun sınıfını genişletir Application
. Sonra içinde geçersiz kılma yöntemini kullanabiliriz onTrimMemory()
.
Uygulamanın arka plana gidip gitmediğini tespit etmek için şunu kullanacağız:
@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Works for Activity
// Get called every-time when application went to background.
}
else if (level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { // Works for FragmentActivty
}
}
FragmentActivity
siz de eklemek isteyebilirsiniz level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE
.
OnUserLeaveHint kullanmayı düşünün. Bu yalnızca uygulamanız arka plana girdiğinde çağrılacaktır. onPause, başka nedenlerle çağrılabileceğinden, ele alınması gereken köşe kasalara sahip olacaktır; örneğin kullanıcı uygulamanızda ayarlar sayfanız gibi başka bir etkinlik açarsa, ana etkinliğinizin onPause yöntemi uygulamanızda bulunsa bile çağrılır; ne olduğunu izlemek, sadece sorduğunuz şeyi yapan onUserLeaveHint geri aramasını kullanabileceğiniz zaman hatalara yol açacaktır.
UserLeaveHint üzerinde çağrıldığında, bir boolean inBackground bayrağını true olarak ayarlayabilirsiniz. OnResume çağrıldığında, yalnızca inBackground bayrağı ayarlanmışsa ön plana geri döndüğünüzü varsayalım. Bunun nedeni, kullanıcı yalnızca ayarlar menünüzdeyse ve uygulamadan hiç ayrılmadıysa onResume'un ana etkinliğinizde de çağrılmasıdır.
Kullanıcı ayarlar ekranınızdayken ana sayfa düğmesine basarsa, ayarlar etkinliğinizde onUserLeaveHint'in çağrıldığını ve ayarlar etkinliğinizde Resume öğesine geri dönüleceğini unutmayın. Bu algılama kodunu ana faaliyetinizde sadece bu kullanım durumunu kaçıracaksınız. Bu kodu, kodu çoğaltmadan tüm etkinliklerinizde kullanmak için, Etkinliği genişleten ve ortak kodunuzu içine koyan soyut bir etkinlik sınıfına sahip olun. O zaman sahip olduğunuz her etkinlik bu soyut etkinliği genişletebilir.
Örneğin:
public abstract AbstractActivity extends Activity {
private static boolean inBackground = false;
@Override
public void onResume() {
if (inBackground) {
// You just came from the background
inBackground = false;
}
else {
// You just returned from another activity within your own app
}
}
@Override
public void onUserLeaveHint() {
inBackground = true;
}
}
public abstract MainActivity extends AbstractActivity {
...
}
public abstract SettingsActivity extends AbstractActivity {
...
}
ActivityLifecycleCallback'ler ilgi çekici olabilir, ancak iyi belgelenmemiştir.
Yine de, registerActivityLifecycleCallbacks () öğesini çağırırsanız , Etkinlikler oluşturulduğunda, yok edildiğinde, vb. İçin geri arama alabilmeniz gerekir. Etkinlik için getComponentName () öğesini çağırabilirsiniz .
Android.arch.lifecycle paketi yaşam döngüsü farkında bileşenleri oluşturmasına izin verin sınıflar ve arayüzler sağlar
Uygulamanız LifecycleObserver arayüzünü uygulamalıdır:
public class MyApplication extends Application implements LifecycleObserver {
@Override
public void onCreate() {
super.onCreate();
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
private void onAppBackgrounded() {
Log.d("MyApp", "App in background");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
private void onAppForegrounded() {
Log.d("MyApp", "App in foreground");
}
}
Bunu yapmak için build.gradle dosyanıza bu bağımlılığı eklemeniz gerekir:
dependencies {
implementation "android.arch.lifecycle:extensions:1.1.1"
}
Google tarafından önerildiği gibi, yaşam döngüsü etkinlik yöntemlerinde yürütülen kodu en aza indirmelisiniz:
Yaygın bir örüntü, bağımlı bileşenlerin eylemlerini yaşam döngüsü aktivite ve parça yöntemlerinde uygulamaktır. Bununla birlikte, bu model, kodun zayıf bir organizasyonuna ve hataların çoğalmasına yol açar. Yaşam döngüsüne duyarlı bileşenleri kullanarak, bağımlı bileşenlerin kodunu yaşam döngüsü yöntemlerinden ve bileşenlerin kendilerine taşıyabilirsiniz.
Daha fazla bilgiyi buradan edinebilirsiniz: https://developer.android.com/topic/libraries/architecture/lifecycle
Uygulamanızda geri aramayı ekleyin ve kök etkinliğini aşağıdaki gibi kontrol edin:
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (activity.isTaskRoot() && !(activity instanceof YourSplashScreenActivity)) {
Log.e(YourApp.TAG, "Reload defaults on restoring from background.");
loadDefaults();
}
}
});
}
Github app-foreground-background-listen üzerine bir proje oluşturdum
Uygulamanızdaki tüm Etkinlik için bir BaseActivity oluşturun.
public class BaseActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
public static boolean isAppInFg = false;
public static boolean isScrInFg = false;
public static boolean isChangeScrFg = false;
@Override
protected void onStart() {
if (!isAppInFg) {
isAppInFg = true;
isChangeScrFg = false;
onAppStart();
}
else {
isChangeScrFg = true;
}
isScrInFg = true;
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
if (!isScrInFg || !isChangeScrFg) {
isAppInFg = false;
onAppPause();
}
isScrInFg = false;
}
public void onAppStart() {
// Remove this toast
Toast.makeText(getApplicationContext(), "App in foreground", Toast.LENGTH_LONG).show();
// Your code
}
public void onAppPause() {
// Remove this toast
Toast.makeText(getApplicationContext(), "App in background", Toast.LENGTH_LONG).show();
// Your code
}
}
Şimdi bu BaseActivity'yi MainActivity gibi tüm Aktivitelerinizin süper sınıfı olarak kullanın, BaseActivity'yi genişletir ve uygulamanızı başlattığınızda onAppStart çağrılır ve uygulama herhangi bir ekrandan arka plana gittiğinde onAppPause () çağrılır.
ProcessLifecycleOwner ile bu oldukça kolay
Bu bağımlılıkları ekle
implementation "android.arch.lifecycle:extensions:$project.archLifecycleVersion"
kapt "android.arch.lifecycle:compiler:$project.archLifecycleVersion"
In KOTLIN :
class ForegroundBackgroundListener : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun startSomething() {
Log.v("ProcessLog", "APP IS ON FOREGROUND")
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stopSomething() {
Log.v("ProcessLog", "APP IS IN BACKGROUND")
}
}
Sonra temel faaliyetinizde:
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get()
.lifecycle
.addObserver(
ForegroundBackgroundListener()
.also { appObserver = it })
}
Bu konuyla ilgili makaleme bakın: https://medium.com/@egek92/how-to-actually-detect-foreground-background-changes-in-your-android-application-without-wanting-9719cc822c48
Bir yaşam döngüsü gözlemcisi ekleyerek ProcessLifecycleOwner'ı kullanabilirsiniz .
public class ForegroundLifecycleObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onAppCreated() {
Timber.d("onAppCreated() called");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppStarted() {
Timber.d("onAppStarted() called");
}
@OnLifecycleEvent(Event.ON_RESUME)
public void onAppResumed() {
Timber.d("onAppResumed() called");
}
@OnLifecycleEvent(Event.ON_PAUSE)
public void onAppPaused() {
Timber.d("onAppPaused() called");
}
@OnLifecycleEvent(Event.ON_STOP)
public void onAppStopped() {
Timber.d("onAppStopped() called");
}
}
daha sonra, onCreate()
Uygulama sınıfınızın üzerinde şunu çağırırsınız:
ProcessLifecycleOwner.get().getLifecycle().addObserver(new ForegroundLifecycleObserver());
bununla birlikte arka planda gittiğinde gerçekleşen olayları ON_PAUSE
ve ON_STOP
uygulamanızı yakalayabileceksiniz .
Uygulamanın ne zaman arka plan / ön plana gittiğini size söyleyecek basit bir yaşam döngüsü yöntemi yoktur.
Bunu basit bir şekilde yaptım. Uygulama arka plan / ön plan aşamasını tespit etmek için aşağıdaki talimatları izleyin.
Biraz geçici bir çözümle mümkündür. Burada, ActivityLifecycleCallbacks kurtarmaya gelir. Adım adım ilerleyeyim.
İlk olarak, android.app.Application öğesini genişleten ve ActivityLifecycleCallbacks arabirimini uygulayan bir sınıf oluşturun . Application.onCreate () içinde geri aramayı kaydedin.
public class App extends Application implements
Application.ActivityLifecycleCallbacks {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
}
Aşağıdaki gibi Manifest'te “App” sınıfını kaydedin <application android:name=".App"
,.
Uygulama ön planda olduğunda başlangıç durumunda en az bir Etkinlik olur ve uygulama arka planda olduğunda başlangıç durumunda hiç Etkinlik olmaz.
“App” sınıfında aşağıdaki 2 değişkeni bildirin.
private int activityReferences = 0;
private boolean isActivityChangingConfigurations = false;
activityReferences
etkinliklerin sayısı sayısı tutacak başladı halde. isActivityChangingConfigurations
geçerli Etkinliğin yön değiştirme anahtarı gibi yapılandırma değişikliğinden geçip geçmediğini gösteren bir işarettir.
Aşağıdaki kodu kullanarak uygulamanın ön plana çıkıp çıkmadığını tespit edebilirsiniz.
@Override
public void onActivityStarted(Activity activity) {
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// App enters foreground
}
}
Uygulamanın arka plana gidip gitmediğini nasıl tespit edersiniz.
@Override
public void onActivityStopped(Activity activity) {
isActivityChangingConfigurations = activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// App enters background
}
}
Nasıl çalışır:
Bu, Yaşam Döngüsü yöntemlerinin sırayla çağrılmasıyla yapılan küçük bir numaradır. Bir senaryo boyunca ilerleyeyim.
Kullanıcının Uygulamayı başlattığını ve Başlatıcı Etkinliği A'nın başlatıldığını varsayın. Yaşam Döngüsü çağrıları,
A.onCreate ()
A.onStart () (++ activityReferences == 1) (Uygulama Ön Plana girer)
A.onResume ()
Şimdi A Etkinliği B Etkinliğini başlatır.
A.onPause ()
B.onCreate ()
B.onStart () (++ activityReferences == 2)
B.onResume ()
A.onStop () (--activityReferences == 1)
Ardından kullanıcı Etkinlik B'den geri döner,
B.onPause ()
A.onStart () (++ activityReferences == 2)
A.onResume ()
B.onStop () (--activityReferences == 1)
B.onDestroy ()
Ardından kullanıcı Ana Ekran düğmesine basar,
A.onPause ()
A.onStop () (--activityReferences == 0) (Uygulama Arka Plana Giriyor)
Kullanıcının Geri düğmesi yerine Etkinlik B'den Ana Ekran düğmesine basması durumunda yine de aynı olur ve etkinlik 0
. Bu nedenle, Uygulama Arkaplan giren olarak tespit edebilir.
Peki rolü isActivityChangingConfigurations
nedir? Yukarıdaki senaryoda, Etkinlik B'nin yönlendirmeyi değiştirdiğini varsayalım. Geri arama sırası,
B.onPause ()
B.onStop () (--activityReferences == 0) (Uygulama Arka Plana Giriyor ??)
B.onDestroy ()
B.onCreate ()
B.onStart () (++ activityReferences == 1) (Uygulama Ön Plana Giriyor ??)
B.onResume ()
Bu nedenle isActivityChangingConfigurations
, Etkinlik Yapılandırma değişikliklerinden geçerken senaryodan kaçınmak için ek bir kontrolümüz var .
Uygulamayı tespit etmek için ön plana veya arka plana girmek için iyi bir yöntem buldum. İşte kodum . Umarım bu sana yardımcı olur.
/**
* Custom Application which can detect application state of whether it enter
* background or enter foreground.
*
* @reference http://www.vardhan-justlikethat.blogspot.sg/2014/02/android-solution-to-detect-when-android.html
*/
public abstract class StatusApplication extends Application implements ActivityLifecycleCallbacks {
public static final int STATE_UNKNOWN = 0x00;
public static final int STATE_CREATED = 0x01;
public static final int STATE_STARTED = 0x02;
public static final int STATE_RESUMED = 0x03;
public static final int STATE_PAUSED = 0x04;
public static final int STATE_STOPPED = 0x05;
public static final int STATE_DESTROYED = 0x06;
private static final int FLAG_STATE_FOREGROUND = -1;
private static final int FLAG_STATE_BACKGROUND = -2;
private int mCurrentState = STATE_UNKNOWN;
private int mStateFlag = FLAG_STATE_BACKGROUND;
@Override
public void onCreate() {
super.onCreate();
mCurrentState = STATE_UNKNOWN;
registerActivityLifecycleCallbacks(this);
}
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
// mCurrentState = STATE_CREATED;
}
@Override
public void onActivityStarted(Activity activity) {
if (mCurrentState == STATE_UNKNOWN || mCurrentState == STATE_STOPPED) {
if (mStateFlag == FLAG_STATE_BACKGROUND) {
applicationWillEnterForeground();
mStateFlag = FLAG_STATE_FOREGROUND;
}
}
mCurrentState = STATE_STARTED;
}
@Override
public void onActivityResumed(Activity activity) {
mCurrentState = STATE_RESUMED;
}
@Override
public void onActivityPaused(Activity activity) {
mCurrentState = STATE_PAUSED;
}
@Override
public void onActivityStopped(Activity activity) {
mCurrentState = STATE_STOPPED;
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
mCurrentState = STATE_DESTROYED;
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (mCurrentState == STATE_STOPPED && level >= TRIM_MEMORY_UI_HIDDEN) {
if (mStateFlag == FLAG_STATE_FOREGROUND) {
applicationDidEnterBackground();
mStateFlag = FLAG_STATE_BACKGROUND;
}
}else if (mCurrentState == STATE_DESTROYED && level >= TRIM_MEMORY_UI_HIDDEN) {
if (mStateFlag == FLAG_STATE_FOREGROUND) {
applicationDidDestroyed();
mStateFlag = FLAG_STATE_BACKGROUND;
}
}
}
/**
* The method be called when the application been destroyed. But when the
* device screen off,this method will not invoked.
*/
protected abstract void applicationDidDestroyed();
/**
* The method be called when the application enter background. But when the
* device screen off,this method will not invoked.
*/
protected abstract void applicationDidEnterBackground();
/**
* The method be called when the application enter foreground.
*/
protected abstract void applicationWillEnterForeground();
}
Edit 2: Aşağıda yazdıklarım aslında çalışmaz. Google, ActivityManager.getRunningTasks () çağrısını içeren bir uygulamayı reddetti. Gönderen dokümantasyon , API hata ayıklama ve geliştirme amaçlı olduğu açıkça görülmektedir. GitHub projesini zamanlayıcıları kullanan ve neredeyse iyi olan yeni bir şema ile güncellemek için zamanım olduğunda bu yazıyı güncelleyeceğim.
Edit 1: Bir blog yazısı yazdım ve bunu kolaylaştırmak için basit bir GitHub deposu oluşturdum .
Kabul edilen ve en yüksek puan alan cevapların her ikisi de gerçekten en iyi yaklaşım değildir. En yüksek puan alan cevabın isApplicationBroughtToBackground () uygulaması, Uygulamanın ana Etkinliğinin aynı Uygulamada tanımlanan bir Etkinliğe ulaştığı durumu işlemez, ancak farklı bir Java paketine sahiptir. Bu durumda işe yarayacak bir yol buldum.
Bunu onPause () içinde çağırın, başka bir uygulama başlatıldığından veya kullanıcı ana sayfa düğmesine bastığından uygulamanızın arka plana girip girmediğini size söyleyecektir.
public static boolean isApplicationBroughtToBackground(final Activity activity) {
ActivityManager activityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(1);
// Check the top Activity against the list of Activities contained in the Application's package.
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
try {
PackageInfo pi = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES);
for (ActivityInfo activityInfo : pi.activities) {
if(topActivity.getClassName().equals(activityInfo.name)) {
return false;
}
}
} catch( PackageManager.NameNotFoundException e) {
return false; // Never happens.
}
}
return true;
}
Doğru cevap burada
Uygulamam adında aşağıdaki gibi bir sınıf oluşturun:
public class MyApp implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
private Context context;
public void setContext(Context context)
{
this.context = context;
}
private boolean isInBackground = false;
@Override
public void onTrimMemory(final int level) {
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
isInBackground = true;
Log.d("status = ","we are out");
}
}
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
if(isInBackground){
isInBackground = false;
Log.d("status = ","we are in");
}
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onConfigurationChanged(Configuration configuration) {
}
@Override
public void onLowMemory() {
}
}
Ardından, istediğiniz her yerde (uygulamada başlatılan daha iyi ilk etkinlik) aşağıdaki kodu ekleyin:
MyApp myApp = new MyApp();
registerComponentCallbacks(myApp);
getApplication().registerActivityLifecycleCallbacks(myApp);
Bitti! Şimdi uygulama arka planda status : we are out
olduğunda günlük alıyoruz ve uygulamaya gittiğimizde günlük alıyoruzstatus : we are out
Çözümüm @ d60402'nin cevabından ilham aldı ve aynı zamanda bir zaman penceresine dayanıyor, ancak aşağıdakileri kullanmıyor Timer
:
public abstract class BaseActivity extends ActionBarActivity {
protected boolean wasInBackground = false;
@Override
protected void onStart() {
super.onStart();
wasInBackground = getApp().isInBackground;
getApp().isInBackground = false;
getApp().lastForegroundTransition = System.currentTimeMillis();
}
@Override
protected void onStop() {
super.onStop();
if( 1500 < System.currentTimeMillis() - getApp().lastForegroundTransition )
getApp().isInBackground = true;
}
protected SingletonApplication getApp(){
return (SingletonApplication)getApplication();
}
}
burada sınıfın SingletonApplication
bir uzantısıdır Application
:
public class SingletonApplication extends Application {
public boolean isInBackground = false;
public long lastForegroundTransition = 0;
}
Bunu Google Analytics EasyTracker ile kullanıyordum ve işe yaradı. Basit bir tamsayı kullanarak aradığınız şeyi yapmak için genişletilebilir.
public class MainApplication extends Application {
int isAppBackgrounded = 0;
@Override
public void onCreate() {
super.onCreate();
appBackgroundedDetector();
}
private void appBackgroundedDetector() {
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
EasyTracker.getInstance(MainApplication.this).activityStart(activity);
}
@Override
public void onActivityResumed(Activity activity) {
isAppBackgrounded++;
if (isAppBackgrounded > 0) {
// Do something here
}
}
@Override
public void onActivityPaused(Activity activity) {
isAppBackgrounded--;
}
@Override
public void onActivityStopped(Activity activity) {
EasyTracker.getInstance(MainApplication.this).activityStop(activity);
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
});
}
}
Ben biraz geç biliyorum ama ben aşağıdaki gibi yaptım ve bu mükemmel çalışır tüm bu cevaplar bazı sorunlar var düşünüyorum.
şöyle bir aktivite yaşam döngüsü geri çağrısı oluşturun:
class ActivityLifeCycle implements ActivityLifecycleCallbacks{
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(Activity activity) {
}
Activity lastActivity;
@Override
public void onActivityResumed(Activity activity) {
//if (null == lastActivity || (activity != null && activity == lastActivity)) //use this condition instead if you want to be informed also when app has been killed or started for the first time
if (activity != null && activity == lastActivity)
{
Toast.makeText(MyApp.this, "NOW!", Toast.LENGTH_LONG).show();
}
lastActivity = activity;
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
}
ve aşağıdaki gibi uygulama sınıfınıza kaydetmeniz yeterlidir:
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifeCycle());
}
Bu, Android'deki en karmaşık sorulardan biri gibi görünüyor (çünkü bu yazı itibariyle) Android'in iOS eşdeğerlerine applicationDidEnterBackground()
veya applicationWillEnterForeground()
geri aramalarına sahip değil . @Jenzz tarafından bir araya getirilen bir AppState Kütüphanesi kullandım .
[AppState], uygulama durumu değişikliklerini izleyen RxJava tabanlı basit ve reaktif bir Android kütüphanesidir. Uygulama arka plana girdiğinde ve ön plana geri döndüğünde aboneleri bilgilendirir.
Bu benim app tam olarak ihtiyaç duyduğu ortaya çıktı, çünkü özellikle benim app birden fazla aktivite vardı, bu yüzden sadece kontrol onStart()
veya onStop()
bir aktivite onu kesecek değildi.
İlk önce bu bağımlılıkları derecelendirmek için ekledim:
dependencies {
compile 'com.jenzz.appstate:appstate:3.0.1'
compile 'com.jenzz.appstate:adapter-rxjava2:3.0.1'
}
Ardından, bu satırları kodunuzdaki uygun bir yere eklemek basit bir konuydu:
//Note that this uses RxJava 2.x adapter. Check the referenced github site for other ways of using observable
Observable<AppState> appState = RxAppStateMonitor.monitor(myApplication);
//where myApplication is a subclass of android.app.Application
appState.subscribe(new Consumer<AppState>() {
@Override
public void accept(@io.reactivex.annotations.NonNull AppState appState) throws Exception {
switch (appState) {
case FOREGROUND:
Log.i("info","App entered foreground");
break;
case BACKGROUND:
Log.i("info","App entered background");
break;
}
}
});
Gözlenebilirlere nasıl abone olduğunuza bağlı olarak, bellek sızıntılarını önlemek için aboneliğinizi iptal etmeniz gerekebilir. Yine github sayfasında daha fazla bilgi .
Bu @ d60402'nin cevabının değiştirilmiş versiyonudur: https://stackoverflow.com/a/15573121/4747587
Orada belirtilen her şeyi yapın. Ama bunun yerine bir sahip Base Activity
ve her aktivite için bir ebeveyn olarak belirttik ve geçersiz kılma onResume()
ve onPause
aşağıda yapın:
Uygulama sınıfınıza şu satırı ekleyin:
registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks geri arama);
Bu callback
, tüm etkinlik yaşam döngüsü yöntemlerine sahiptir ve şimdi onActivityResumed()
ve öğelerini geçersiz kılabilirsiniz onActivityPaused()
.
Bu özete bir göz atın: https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b
Bunu kolayca ActivityLifecycleCallbacks
ve ComponentCallbacks2
aşağıdaki gibi bir şeyle başarabilirsiniz .
AppLifeCycleHandler
Bahsedilen arabirimlerin üzerinde bir sınıf oluşturun .
package com.sample.app;
import android.app.Activity;
import android.app.Application;
import android.content.ComponentCallbacks2;
import android.content.res.Configuration;
import android.os.Bundle;
/**
* Created by Naveen on 17/04/18
*/
public class AppLifeCycleHandler
implements Application.ActivityLifecycleCallbacks, ComponentCallbacks2 {
AppLifeCycleCallback appLifeCycleCallback;
boolean appInForeground;
public AppLifeCycleHandler(AppLifeCycleCallback appLifeCycleCallback) {
this.appLifeCycleCallback = appLifeCycleCallback;
}
@Override
public void onActivityResumed(Activity activity) {
if (!appInForeground) {
appInForeground = true;
appLifeCycleCallback.onAppForeground();
}
}
@Override
public void onTrimMemory(int i) {
if (i == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
appInForeground = false;
appLifeCycleCallback.onAppBackground();
}
}
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
@Override
public void onConfigurationChanged(Configuration configuration) {
}
@Override
public void onLowMemory() {
}
interface AppLifeCycleCallback {
void onAppBackground();
void onAppForeground();
}
}
Senin sınıfında uzanan Application
uygulamak AppLifeCycleCallback
uygulama ön planda ve arka plan arasında geçiş yaparken geri aramalar alır. Aşağıdaki gibi bir şey.
public class BaseApplication extends Application implements AppLifeCycleHandler.AppLifeCycleCallback{
@Override
public void onCreate() {
super.onCreate();
AppLifeCycleHandler appLifeCycleHandler = new AppLifeCycleHandler(this);
registerActivityLifecycleCallbacks(appLifeCycleHandler);
registerComponentCallbacks(appLifeCycleHandler);
}
@Override
public void onAppBackground() {
Log.d("LifecycleEvent", "onAppBackground");
}
@Override
public void onAppForeground() {
Log.d("LifecycleEvent", "onAppForeground");
}
}
Bu yardımcı olur umarım.
EDIT Alternatif olarak artık Yaşam döngüsü farkında mimari bileşenini kullanabilirsiniz.
Zaman damgalarını kontrol etmeden rotasyonu da ele alan herhangi bir yaklaşım bulamadığımdan, şimdi de bunu uygulamamızda nasıl yaptığımızı paylaştığımı düşündüm. Bu cevaba https://stackoverflow.com/a/42679191/5119746 adresindeki tek ekleme , yönlendirmeyi de dikkate almamızdır.
class MyApplication : Application(), Application.ActivityLifecycleCallbacks {
// Members
private var mAppIsInBackground = false
private var mCurrentOrientation: Int? = null
private var mOrientationWasChanged = false
private var mResumed = 0
private var mPaused = 0
Sonra, geri aramalar için önce özgeçmişimiz var:
// ActivityLifecycleCallbacks
override fun onActivityResumed(activity: Activity?) {
mResumed++
if (mAppIsInBackground) {
// !!! App came from background !!! Insert code
mAppIsInBackground = false
}
mOrientationWasChanged = false
}
Ve onActivityStopped:
override fun onActivityStopped(activity: Activity?) {
if (mResumed == mPaused && !mOrientationWasChanged) {
// !!! App moved to background !!! Insert code
mAppIsInBackground = true
}
Ve sonra, ek: İşte yön değişikliklerini kontrol etme:
override fun onConfigurationChanged(newConfig: Configuration) {
if (newConfig.orientation != mCurrentOrientation) {
mCurrentOrientation = newConfig.orientation
mOrientationWasChanged = true
}
super.onConfigurationChanged(newConfig)
}
Bu kadar. Umarım bu birine yardımcı olur :)
Bu çözümü aşağıdakileri kullanarak genişletebiliriz LiveData
:
class AppForegroundStateLiveData : LiveData<AppForegroundStateLiveData.State>() {
private var lifecycleListener: LifecycleObserver? = null
override fun onActive() {
super.onActive()
lifecycleListener = AppLifecycleListener().also {
ProcessLifecycleOwner.get().lifecycle.addObserver(it)
}
}
override fun onInactive() {
super.onInactive()
lifecycleListener?.let {
this.lifecycleListener = null
ProcessLifecycleOwner.get().lifecycle.removeObserver(it)
}
}
internal inner class AppLifecycleListener : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onMoveToForeground() {
value = State.FOREGROUND
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onMoveToBackground() {
value = State.BACKGROUND
}
}
enum class State {
FOREGROUND, BACKGROUND
}
}
Şimdi bu LiveData'ya abone olabilir ve gerekli olayları yakalayabiliriz. Örneğin:
appForegroundStateLiveData.observeForever { state ->
when(state) {
AppForegroundStateLiveData.State.FOREGROUND -> { /* app move to foreground */ }
AppForegroundStateLiveData.State.BACKGROUND -> { /* app move to background */ }
}
}
Bu cevaplar doğru görünmüyor. Bu yöntemler, başka bir etkinlik başladığında ve bittiğinde de çağrılır. Yapabileceğiniz şey global bir bayrak tutmaktır (evet, globaller kötü :) ve her yeni aktiviteye başladığınızda bunu true olarak ayarlayın. Her etkinliğin onCreate öğesinde false olarak ayarlayın. Ardından, onPause'da bu bayrağı kontrol edersiniz. Yanlışsa, uygulamanız arka plana gider veya öldürülür.