मैं एक ऐसे ऐप को लिखने की कोशिश कर रहा हूं जो कुछ विशिष्ट करता है जब इसे कुछ समय के बाद अग्रभूमि में वापस लाया जाता है। क्या पता लगाने का कोई तरीका है कि किसी ऐप को बैकग्राउंड में भेजा जाए या अग्रभूमि में लाया जाए?
मैं एक ऐसे ऐप को लिखने की कोशिश कर रहा हूं जो कुछ विशिष्ट करता है जब इसे कुछ समय के बाद अग्रभूमि में वापस लाया जाता है। क्या पता लगाने का कोई तरीका है कि किसी ऐप को बैकग्राउंड में भेजा जाए या अग्रभूमि में लाया जाए?
जवाबों:
onPause()
और onResume()
तरीकों जब आवेदन फिर पृष्ठभूमि करने के लिए और अग्रभूमि में लाया जाता है कहा जाता है। हालांकि, उन्हें तब भी बुलाया जाता है जब आवेदन पहली बार शुरू किया जाता है और इसे मारने से पहले। आप गतिविधि में अधिक पढ़ सकते हैं ।
पृष्ठभूमि या अग्रभूमि में आवेदन की स्थिति प्राप्त करने के लिए कोई प्रत्यक्ष दृष्टिकोण नहीं है, लेकिन यहां तक कि मैंने इस मुद्दे का सामना किया है onWindowFocusChanged
और इसके साथ समाधान पाया है onStop
।
अधिक जानकारी के लिए यहां Android की जांच करें : यह पता लगाने के लिए समाधान कि एंड्रॉइड ऐप कब बैकग्राउंड में जाता है और getRunningTasks या getRunningAppProcesses के बिना अग्रभूमि में वापस आ जाता है ।
मार्च 2018 अपडेट : अब एक बेहतर समाधान है। ProcessLifecycleOwner देखें । आपको नए आर्किटेक्चर घटकों का उपयोग करने की आवश्यकता होगी 1.1.0 (इस समय नवीनतम) लेकिन यह विशेष रूप से ऐसा करने के लिए डिज़ाइन किया गया है।
इस उत्तर में एक सरल नमूना प्रदान किया गया है लेकिन मैंने इसके बारे में एक नमूना ऐप और एक ब्लॉग पोस्ट लिखा है।
जब से मैंने 2014 में इसे वापस लिखा, तब से अलग-अलग समाधान सामने आए। कुछ ने काम किया, कुछ ने काम करने के लिए सोचा था, लेकिन खामियां थीं (मेरी सहित!) और हम, एक समुदाय के रूप में (एंड्रॉइड) ने परिणामों के साथ रहना सीखा और विशेष मामलों के लिए वर्कअराउंड लिखा।
कोड का एक भी स्निपेट कभी नहीं मानें कि आप जिस समाधान की तलाश कर रहे हैं, यह संभावना नहीं है; बेहतर अभी तक, यह समझने की कोशिश करें कि यह क्या करता है और यह क्यों करता है।
MemoryBoss
वर्ग वास्तव में कभी के रूप में यहाँ लिखा मेरे द्वारा इस्तेमाल किया गया था, यह सिर्फ छद्म कोड है कि काम का क्या हुआ का एक टुकड़ा था।
जब तक आपके पास नए आर्किटेक्चर घटकों का उपयोग न करने का वैध कारण है (और कुछ हैं, खासकर यदि आप सुपर पुरानी एपिस को लक्षित करते हैं), तो आगे बढ़ें और उनका उपयोग करें। वे सही से बहुत दूर हैं, लेकिन न तो थे ComponentCallbacks2
।
अद्यतन / सूचना (नवंबर 2015) : लोग दो टिप्पणियां कर रहे हैं, पहला यह है कि >=
इसके बजाय इसका उपयोग किया जाना चाहिए ==
क्योंकि प्रलेखन में कहा गया है कि आपको सटीक मानों की जांच नहीं करनी चाहिए । यह अधिकांश मामलों के लिए ठीक है, लेकिन ध्यान रखें कि यदि आप केवल ऐप के बैकग्राउंड में जाने पर कुछ करने की परवाह करते हैं , तो आपको == का उपयोग करना होगा और इसे दूसरे समाधान के साथ भी संयोजित करना होगा (जैसे कि एक्टिविटी लाइफसाइकल कॉलबैक), या आप आपका इच्छित प्रभाव नहीं मिल सकता है। उदाहरण (और यह मेरे साथ हुआ) यह है कि यदि आप लॉक करना चाहते हैंपासवर्ड स्क्रीन के साथ आपका ऐप जब यह पृष्ठभूमि पर जाता है (जैसे 1Password अगर आप इससे परिचित हैं), तो आप गलती से अपने ऐप को लॉक कर सकते हैं यदि आप मेमोरी पर कम चलाते हैं और अचानक परीक्षण कर रहे हैं >= TRIM_MEMORY
, क्योंकि एंड्रॉइड एक LOW MEMORY
कॉल को ट्रिगर करेगा और वह है तुम्हारी तुलना में अधिक है। इसलिए सावधान रहें कि आप कैसे / क्या परीक्षण करते हैं।
इसके अतिरिक्त, कुछ लोगों ने पूछा है कि जब आप वापस आते हैं, तो कैसे पता लगाया जाए।
सबसे आसान तरीका जिसके बारे में मैं नीचे बता सकता हूं, लेकिन चूंकि कुछ लोग इससे अपरिचित हैं, इसलिए मैं यहां कुछ छद्म कोड जोड़ रहा हूं। आप YourApplication
और MemoryBoss
वर्गों को मानकर , अपने में class BaseActivity extends Activity
(आपको एक बनाने की आवश्यकता होगी यदि आपके पास एक नहीं है)।
@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);
}
}
मैं सलाह देता हूं कि क्योंकि संवाद एक गतिविधि को रोक सकता है इसलिए मैं शर्त लगाता हूं कि आप नहीं चाहते कि आपका ऐप "यह पृष्ठभूमि में चला गया" यदि आप सभी ने एक पूर्ण स्क्रीन संवाद प्रदर्शित किया था, लेकिन आपका लाभ भिन्न हो सकता है।
और बस यही। अगर ब्लॉक में कोड होगा केवल एक बार निष्पादित किया , भले ही आप किसी अन्य गतिविधि के लिए जाना, नया एक (जो भी extends BaseActivity
) रिपोर्ट करेंगे wasInBackground
है false
, तो यह कोड निष्पादित नहीं होगा जब तक onMemoryTrimmed
कहा जाता है और झंडा फिर से सही पर सेट है ।
उम्मीद है की वो मदद करदे।
अद्यतन / नोट (अप्रैल 2015) : इससे पहले कि आप सभी इस कोड पर कॉपी और पेस्ट करें, ध्यान दें कि मुझे कुछ ऐसे उदाहरण मिले हैं जहां यह 100% विश्वसनीय नहीं हो सकता है और सर्वोत्तम परिणाम प्राप्त करने के लिए अन्य तरीकों के साथ जोड़ा जाना चाहिए । उल्लेखनीय रूप से, दो ज्ञात उदाहरण हैं जहां onTrimMemory
कॉल बैक को निष्पादित करने की गारंटी नहीं है:
यदि आपका फ़ोन स्क्रीन पर दिखाई देता है, जबकि आपका ऐप दिखाई देता है (जैसे कि nn मिनट के बाद आपका डिवाइस लॉक हो जाता है), इस कॉलबैक को (या हमेशा नहीं) कहा जाता है क्योंकि लॉकस्क्रीन अभी शीर्ष पर है, लेकिन आपका ऐप अभी भी "चल रहा है" यद्यपि कवर किया हुआ है।
यदि आपका डिवाइस मेमोरी (और मेमोरी स्ट्रेस के तहत) पर अपेक्षाकृत कम है, तो ऑपरेटिंग सिस्टम इस कॉल को अनदेखा करता है और सीधे अधिक महत्वपूर्ण स्तरों पर जाता है।
अब, आपके लिए यह जानना कितना ज़रूरी है कि आपका ऐप कब बैकग्राउंड में चला गया है, आपको गतिविधि जीवनचक्र और व्हाट्सएप पर नज़र रखने के साथ इस समाधान का विस्तार करने की आवश्यकता हो सकती है या नहीं।
बस उपरोक्त को ध्यान में रखें और एक अच्छी क्यूए टीम है;)
अद्यतन का अंत
यह देर हो सकती है लेकिन आइसक्रीम सैंडविच (एपीआई 14) और इसके बाद के संस्करण में एक विश्वसनीय विधि है ।
यह बताता है कि जब आपके ऐप में UI दिखाई नहीं देता है, तो कॉलबैक शुरू हो जाता है। कॉलबैक, जिसे आप एक कस्टम वर्ग में लागू कर सकते हैं, को ComponentCallbacks2 (हाँ, दो के साथ) कहा जाता है । यह कॉलबैक केवल एपीआई स्तर 14 (आइसक्रीम सैंडविच) और इसके बाद के संस्करण में उपलब्ध है।
आपको मूल रूप से विधि के लिए एक कॉल मिलता है:
public abstract void onTrimMemory (int level)
स्तर 20 या अधिक विशेष रूप से है
public static final int TRIM_MEMORY_UI_HIDDEN
मैं यह परीक्षण कर रहा हूं और यह हमेशा काम करता है, क्योंकि स्तर 20 सिर्फ एक "सुझाव" है जिसे आप कुछ संसाधनों को जारी करना चाहते हैं क्योंकि आपका ऐप अब दिखाई नहीं देता है।
आधिकारिक डॉक्स को उद्धृत करने के लिए:
OnTrimMemory (int) के लिए स्तर: प्रक्रिया उपयोगकर्ता इंटरफ़ेस दिखा रही थी, और अब ऐसा नहीं कर रही है। यूआई के साथ बड़े आवंटन को इस बिंदु पर जारी किया जाना चाहिए ताकि स्मृति को बेहतर तरीके से प्रबंधित किया जा सके।
बेशक, आप यह लागू वास्तव में यह क्या कहते हैं (स्मृति साफ है कि कुछ समय में उपयोग नहीं किया जा करने के लिए करना चाहिए, कुछ संग्रह है कि अप्रयुक्त बैठे, आदि संभावनाएं अनंत हैं (अन्य संभावित लिए सरकारी दस्तावेज़ देख सकेंगे स्पष्ट अधिक महत्वपूर्ण स्तर)।
लेकिन, दिलचस्प बात यह है कि ओएस आपको बता रहा है: अरे, आपका ऐप पृष्ठभूमि पर चला गया!
वही है जो आप पहली बार में जानना चाहते थे।
जब आप वापस आ गए तो आप कैसे निर्धारित करते हैं?
खैर यह आसान है, मुझे यकीन है कि आपके पास एक "बेसएक्टिविटी" है, ताकि आप अपने onResume () का उपयोग इस तथ्य को चिह्नित करने के लिए कर सकें कि आप वापस आ गए हैं। क्योंकि केवल समय आप कह रहे हैं कि आप वापस नहीं हैं जब आप वास्तव में उपरोक्त onTrimMemory
विधि के लिए कॉल प्राप्त करते हैं ।
यह काम करता हैं। आपको झूठी सकारात्मकता नहीं मिलती। यदि कोई गतिविधि फिर से शुरू हो रही है, तो आप 100% बार वापस आ जाते हैं। यदि उपयोगकर्ता फिर से पीछे जाता है, तो आपको एक और onTrimMemory()
कॉल मिलती है ।
आपको अपनी गतिविधियाँ (या बेहतर अभी तक, एक कस्टम वर्ग) का पता लगाने की आवश्यकता है।
यह गारंटी देने का सबसे आसान तरीका है कि आप इसे हमेशा प्राप्त करें, इस तरह से एक साधारण वर्ग बनाना है:
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.
}
}
इसका उपयोग करने के लिए, आपके एप्लिकेशन कार्यान्वयन में ( आपके पास एक, राइट? ), कुछ इस तरह से करें:
MemoryBoss mMemoryBoss;
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
mMemoryBoss = new MemoryBoss();
registerComponentCallbacks(mMemoryBoss);
}
}
आप एक बनाते हैं, तो Interface
आप एक जोड़ सकते हैं else
कि करने के लिए if
और लागू ComponentCallbacks
(बिना 2) एपीआई 14. नीचे कुछ भी में प्रयोग किया जाता कॉलबैक केवल यही onLowMemory()
तरीका है और कहा जाता है नहीं प्राप्त करता है जब आप पृष्ठभूमि में जाते , लेकिन आप इसे ट्रिम स्मृति का उपयोग करना चाहिए ।
अब अपना ऐप लॉन्च करें और घर दबाएं। आपकी onTrimMemory(final int level)
विधि को बुलाया जाना चाहिए (संकेत: लॉगिंग जोड़ें)।
अंतिम चरण कॉलबैक से अपंजीकृत करना है। संभवत: सबसे अच्छी जगह onTerminate()
आपके ऐप की विधि है, लेकिन , यह तरीका असली डिवाइस पर नहीं मिलता है:
/** * 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. */
इसलिए जब तक आपके पास वास्तव में ऐसी स्थिति नहीं है जहां आप अब पंजीकृत नहीं होना चाहते हैं, तो आप सुरक्षा को अनदेखा कर सकते हैं, क्योंकि आपकी प्रक्रिया वैसे भी ओएस स्तर पर मर रही है।
यदि आप किसी बिंदु पर अपंजीकृत करने का निर्णय लेते हैं (यदि आप, उदाहरण के लिए, अपने ऐप को साफ करने और मरने के लिए शटडाउन तंत्र प्रदान करें), तो आप कर सकते हैं:
unregisterComponentCallbacks(mMemoryBoss);
और बस।
level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
आपके अपडेट में समस्या से बचने के लिए उपयोग करता हूं , बिंदु 2। बिंदु 1 के बारे में, यह मेरे लिए चिंता की बात नहीं है, क्योंकि ऐप वास्तव में पृष्ठभूमि पर नहीं गया है, इसलिए यह काम करने का तरीका है।
यहां बताया गया है कि मैं इसे कैसे हल कर पाया हूं। यह इस आधार पर काम करता है कि गतिविधि संक्रमणों के बीच एक समय संदर्भ का उपयोग करने से सबसे अधिक संभावना पर्याप्त साक्ष्य प्रदान करेगी कि एक ऐप "पृष्ठभूमि में" रहा है या नहीं।
सबसे पहले, मैंने एक android.app.Application इंस्टेंस का उपयोग किया है (चलो इसे MyApplication कहते हैं) जिसमें एक टाइमर, एक टाइमर, एक अधिकतम मिलीसेकंड का प्रतिनिधित्व करने के लिए एक निरंतरता है जो एक गतिविधि से दूसरे में संक्रमण का कारण बन सकती है (मैं गया था) 2s के मान के साथ), और यह इंगित करने के लिए एक बूलियन कि ऐप "पृष्ठभूमि में" था या नहीं:
public class MyApplication extends Application {
private Timer mActivityTransitionTimer;
private TimerTask mActivityTransitionTimerTask;
public boolean wasInBackground;
private final long MAX_ACTIVITY_TRANSITION_TIME_MS = 2000;
...
आवेदन भी टाइमर / कार्य शुरू करने और रोकने के लिए दो तरीके प्रदान करता है:
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;
}
इस समाधान का अंतिम टुकड़ा onResume () और onPause () की सभी गतिविधियों में से प्रत्येक विधि में एक कॉल जोड़ना है, या, अधिमानतः, एक आधार गतिविधि जिसमें से आपकी सभी ठोस गतिविधियाँ विरासत में मिली हैं:
@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();
}
तो उस स्थिति में जब उपयोगकर्ता आपके ऐप की गतिविधियों के बीच नेविगेट कर रहा होता है, तब प्रस्थान की गतिविधि का ऑनपॉज टाइमर शुरू करता है, लेकिन अधिकतम संक्रमण समय तक पहुंचने से पहले ही लगभग नई गतिविधि टाइमर में प्रवेश कर जाती है। और इसलिए InBackground गलत होगा ।
दूसरी ओर जब कोई गतिविधि लॉन्चर से अग्रभूमि पर आती है, तो डिवाइस वेक अप, एंड फोन कॉल आदि की संभावना होती है, इस घटना से पहले निष्पादित होने वाले टाइमर कार्य की संभावना अधिक होती है, और इस तरह InInBackground को सही पर सेट किया गया था ।
संपादित करें: नए आर्किटेक्चर घटक कुछ आशाजनक लाए हैं: ProcessLifecycleOwner , @ vokilam का उत्तर देखें
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
}
}
}
हाँ। मुझे पता है कि इस सरल समाधान कार्यों पर विश्वास करना मुश्किल है क्योंकि हमारे पास यहां बहुत सारे अजीब समाधान हैं।
लेकिन उम्मीद है।
ProcessLifecycleOwner
एक आशाजनक समाधान भी प्रतीत होता है।
ProcessLifecycleOwner इन घटनाओं के माध्यम से एक पहली गतिविधि के रूप में
ON_START
,ON_RESUME
घटनाओं को भेज देगा ।ON_PAUSE
, एक अंतिम गतिविधि उनके माध्यम से पारित होने के बाद देरी केON_STOP
साथ घटनाओं को भेजा जाएगा । यह देरी लंबे समय तक गारंटी देने के लिए पर्याप्त है कि किसी भी घटना को नहीं भेजा जाएगा अगर गतिविधियों को नष्ट कर दिया जाता है और कॉन्फ़िगरेशन परिवर्तन के कारण इसे फिर से बनाया जाता है।ProcessLifecycleOwner
एक कार्यान्वयन जितना सरल हो सकता है
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())
स्रोत कोड के अनुसार, वर्तमान विलंब मूल्य है 700ms
।
इस सुविधा का उपयोग करने के लिए भी इसकी आवश्यकता है dependencies
:
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
implementation "android.arch.lifecycle:extensions:1.0.0"
और annotationProcessor "android.arch.lifecycle:compiler:1.0.0"
Google की रिपॉजिटरी (यानी google()
) से जोड़ने की आवश्यकता है
मार्टीन मार्कोसिनिस उत्तर (धन्यवाद!) के आधार पर अंत में मुझे एक विश्वसनीय (और बहुत सरल) समाधान मिला।
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;
}
}
}
फिर इसे अपने एप्लिकेशन वर्ग के अपने ऑनक्रिएट () में जोड़ें
public class MyApp extends android.app.Application {
@Override
public void onCreate() {
super.onCreate();
ApplicationLifeCycleHandler handler = new ApplicationLifeCycleHandler();
registerActivityLifecycleCallbacks(handler);
registerComponentCallbacks(handler);
}
}
हम इस विधि का उपयोग करते हैं। यह काम करने के लिए बहुत सरल लगता है, लेकिन यह हमारे ऐप में अच्छी तरह से परीक्षण किया गया था और वास्तव में सभी मामलों में आश्चर्यजनक रूप से अच्छी तरह से काम करता है, जिसमें "होम" बटन द्वारा "रिटर्न" बटन, या स्क्रीन लॉक के बाद होम स्क्रीन पर जाना शामिल है। कोशिश करो।
आइडिया है, जब अग्रभूमि में, पिछले एक को रोकने से पहले एंड्रॉइड हमेशा नई गतिविधि शुरू करता है। यह गारंटी नहीं है, लेकिन यह है कि यह कैसे काम करता है। BTW, Flurry एक ही तर्क का उपयोग करता है (बस एक अनुमान है, मैंने इसकी जाँच नहीं की है, लेकिन यह एक ही घटनाओं पर हुक करता है)।
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
}
}
}
संपादित करें: टिप्पणियों के अनुसार, हम कोड के बाद के संस्करणों में onStart () में चले गए। इसके अलावा, मैं सुपर कॉल्स जोड़ रहा हूं, जो मेरे शुरुआती पोस्ट से गायब थे, क्योंकि यह एक वर्किंग कोड की तुलना में अधिक अवधारणा थी।
onStop is called when the activity is no longer visible to the user
।
यदि आपके ऐप में एक टैब बार विजेट की तरह कई एक्टिविटीज़ और / या स्टैक्ड एक्टीविटीज़ हैं, तो ऑनपॉज़ () और ऑनस्क्यूम () काम नहीं करेगा। एक नई गतिविधि शुरू करने के बाद यानी वर्तमान गतिविधियों को नया बनाने से पहले रोक दिया जाएगा। जब एक गतिविधि "बैक" बटन का उपयोग कर खत्म होती है तो वही लागू होता है।
मुझे दो तरीके मिले हैं जो काम करना चाहते हैं।
पहले वाले को GET_TASKS अनुमति की आवश्यकता होती है और इसमें एक सरल विधि शामिल होती है जो यह जांचती है कि क्या पैकेज के नामों की तुलना करके डिवाइस पर शीर्ष चल रही गतिविधि अनुप्रयोग से संबंधित है:
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;
}
यह विधि Droid-Fu (जिसे अब इग्निशन कहा जाता है) फ्रेमवर्क में मिली।
दूसरी विधि जो मैंने अपने स्वयं को लागू की है, उसे GET_TASKS अनुमति की आवश्यकता नहीं है, जो अच्छा है। इसके बजाय इसे लागू करना थोड़ा अधिक जटिल है।
आपके पास MainApplication class में आपके पास एक वैरिएबल है जो आपके एप्लिकेशन में चल रही गतिविधियों की संख्या को ट्रैक करता है। प्रत्येक गतिविधि के लिए onResume () में आप चर बढ़ाते हैं और ऑनपॉज़ () में आप इसे घटाते हैं।
जब चलने वाली गतिविधियों की संख्या 0 तक पहुँच जाती है, तो आवेदन को पृष्ठभूमि में रखा जाता है यदि निम्न स्थितियाँ सत्य हैं:
जब आप यह पता लगा सकते हैं कि एप्लिकेशन ने पृष्ठभूमि से इस्तीफा दे दिया है, तो यह आसानी से पता लगाया जाता है कि कब इसे वापस अग्रभूमि में लाया जाए।
एक क्लास बनाएं जो फैली हुई हो Application
। तो यह में हम, अपने ओवरराइड विधि का उपयोग कर सकते हैं onTrimMemory()
।
यह पता लगाने के लिए कि आवेदन पृष्ठभूमि में गया, हम उपयोग करेंगे:
@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
आप भी जोड़ सकते हैं level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE
भी।
OnUserLeaveHint का उपयोग करने पर विचार करें। यह तभी कहा जाएगा जब आपका ऐप बैकग्राउंड में चला जाएगा। ऑनपॉज़ के पास संभालने के लिए कोने के मामले होंगे, क्योंकि इसे अन्य कारणों से बुलाया जा सकता है; उदाहरण के लिए यदि उपयोगकर्ता आपके ऐप में कोई अन्य गतिविधि जैसे कि आपके सेटिंग पृष्ठ को खोलता है, तो आपकी मुख्य गतिविधि की ऑनपॉज़ विधि को आपके ऐप में रहने के बावजूद भी कॉल किया जाएगा; ट्रैकिंग क्या हो रही है, बग को बढ़ावा मिलेगा जब आप इसके बजाय बस onUserLeaveHint कॉलबैक का उपयोग कर सकते हैं जो कि आप क्या पूछ रहे हैं।
जब UserLeaveHint पर कॉल किया जाता है, तो आप एक बूलियन inBackground ध्वज को सही पर सेट कर सकते हैं। जब OnResume कहा जाता है, केवल मान लें कि आप अग्रभूमि में वापस आ गए हैं यदि बैकग्राउंड ध्वज को सेट किया गया है। ऐसा इसलिए है क्योंकि यदि उपयोगकर्ता केवल आपकी सेटिंग मेनू में था और ऐप को कभी नहीं छोड़ा तो onResume को आपकी मुख्य गतिविधि पर बुलाया जाएगा।
याद रखें कि यदि उपयोगकर्ता आपकी सेटिंग स्क्रीन में होम बटन को हिट करता है, तो onUserLeaveHint को आपकी सेटिंग गतिविधि में बुलाया जाएगा, और जब वे वापस लौटते हैं, तो आपकी सेटिंग्स गतिविधि में कॉल किया जाएगा। यदि आपके पास आपकी मुख्य गतिविधि में केवल यह पहचान कोड है तो आप इस उपयोग के मामले को याद करेंगे। डुप्लिकेट कोड के बिना आपकी सभी गतिविधियों में इस कोड को रखने के लिए, एक अमूर्त गतिविधि वर्ग होता है जो गतिविधि का विस्तार करता है, और इसमें अपना सामान्य कोड डालता है। फिर आपके पास प्रत्येक गतिविधि इस सार गतिविधि को बढ़ा सकती है।
उदाहरण के लिए:
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 {
...
}
एक्टिविटी लाइफ़साइकलकॉल ब्याज की हो सकती है, लेकिन यह अच्छी तरह से प्रलेखित नहीं है।
हालाँकि, यदि आप registerActivityLifecycleCallbacks () को कॉल करते हैं, तो जब आप गतिविधियाँ बनते हैं, नष्ट हो जाते हैं, आदि के लिए आपको कॉलबैक प्राप्त करने में सक्षम होना चाहिए। आप गतिविधि के लिए getComponentName () कॉल कर सकते हैं ।
android.arch.lifecycle पैकेज वर्गों और इंटरफेस है कि आप जीवन चक्र अवगत घटकों का निर्माण करते हैं प्रदान करता है
आपके एप्लिकेशन को LifecycleObserver इंटरफ़ेस लागू करना चाहिए:
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");
}
}
ऐसा करने के लिए, आपको अपनी build.gradle फ़ाइल में इस निर्भरता को जोड़ने की आवश्यकता है:
dependencies {
implementation "android.arch.lifecycle:extensions:1.1.1"
}
Google द्वारा अनुशंसित के अनुसार, आपको गतिविधियों के जीवनचक्र विधियों में निष्पादित कोड को कम से कम करना चाहिए:
एक सामान्य पैटर्न गतिविधियों और टुकड़े के जीवन चक्र के तरीकों में निर्भर घटकों के कार्यों को लागू करना है। हालांकि, यह पैटर्न कोड के एक खराब संगठन और त्रुटियों के प्रसार की ओर जाता है। जीवनचक्र-जागरूक घटकों का उपयोग करके, आप जीवनचक्र विधियों में से आश्रित घटकों के कोड को स्वयं घटकों में स्थानांतरित कर सकते हैं।
आप यहाँ और अधिक पढ़ सकते हैं: https://developer.android.com/topic/lbooks/altecture/lifecycle
अपने आवेदन में कॉलबैक जोड़ें और इस तरह से रूट गतिविधि के लिए जाँच करें:
@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();
}
}
});
}
मैंने जीथब ऐप-अग्रभूमि-पृष्ठभूमि-सुनो पर एक परियोजना बनाई है
अपने आवेदन में सभी गतिविधि के लिए एक बेसएक्टिविटी बनाएं।
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
}
}
अब इस बेसएक्टिविटी को अपनी सभी गतिविधि के एक सुपर क्लास के रूप में उपयोग करें जैसे कि मेनऐक्टिविटी बेसएक्टिविटी को बढ़ाती है और जब आप अपना एप्लिकेशन शुरू करते हैं तो ऑनएपस्टार्ट को बुलाया जाएगा और जब एप्लिकेशन किसी भी स्क्रीन पर बैकग्राउंड चला जाएगा तो ऑनपॉज़ () कहा जाएगा।
यह बहुत आसान है ProcessLifecycleOwner के
इन निर्भरताओं को जोड़ें
implementation "android.arch.lifecycle:extensions:$project.archLifecycleVersion"
kapt "android.arch.lifecycle:compiler:$project.archLifecycleVersion"
में 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")
}
}
फिर अपनी आधार गतिविधि में:
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get()
.lifecycle
.addObserver(
ForegroundBackgroundListener()
.also { appObserver = it })
}
इस विषय पर मेरा लेख देखें: https://medium.com/@egek92/how-to-actually-detect-foreground-background-changes-in-your-android-application-without-wanting-9719cc822c48
आप ProcessLifecycleOwner का उपयोग करके इसे एक जीवनचक्र पर्यवेक्षक संलग्न कर सकते हैं ।
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");
}
}
तब onCreate()
आपके एप्लिकेशन वर्ग पर आप इसे कहते हैं:
ProcessLifecycleOwner.get().getLifecycle().addObserver(new ForegroundLifecycleObserver());
इसके साथ आप पृष्ठभूमि में जाने पर होने वाली ON_PAUSE
और ON_STOP
आपके एप्लिकेशन की घटनाओं को कैप्चर कर पाएंगे ।
जब कोई संपूर्ण अनुप्रयोग पृष्ठभूमि / अग्रभूमि में जाता है, तो आपको बताने के लिए कोई सीधी जीवन पद्धति नहीं होती है।
मैंने इसे सरल तरीके से किया है। एप्लिकेशन पृष्ठभूमि / अग्रभूमि चरण का पता लगाने के लिए नीचे दिए गए निर्देशों का पालन करें।
थोड़ा वर्कअराउंड के साथ, यह संभव है। यहां, एक्टिविटी लाइफ़साइकल कॉलबैक बचाव में आता है। मुझे चरण-दर-चरण चलो।
सबसे पहले, एक वर्ग है कि फैली बनाने android.app.Application और औजार ActivityLifecycleCallbacks इंटरफ़ेस। Application.onCreate () में, कॉलबैक रजिस्टर करें।
public class App extends Application implements
Application.ActivityLifecycleCallbacks {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
}
नीचे के रूप में मैनिफेस्ट में "ऐप" क्लास रजिस्टर करें <application android:name=".App"
।
शुरू की स्थिति में कम से कम एक गतिविधि तब होगी जब ऐप अग्रभूमि में हो और जब अनुप्रयोग पृष्ठभूमि में हो तो प्रारंभ की गई अवस्था में कोई गतिविधि नहीं होगी।
"अनुप्रयोग" वर्ग में नीचे के रूप में 2 चर घोषित करें।
private int activityReferences = 0;
private boolean isActivityChangingConfigurations = false;
activityReferences
शुरू राज्य में गतिविधियों की संख्या की गिनती रखेंगे । isActivityChangingConfigurations
यह इंगित करने के लिए एक ध्वज है कि क्या वर्तमान गतिविधि एक अभिविन्यास स्विच की तरह कॉन्फ़िगरेशन परिवर्तन से गुजर रही है।
यदि एप्लिकेशन अग्रभूमि में आता है, तो निम्न कोड का उपयोग करके आप यह पता लगा सकते हैं।
@Override
public void onActivityStarted(Activity activity) {
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// App enters foreground
}
}
यह पता लगाने के लिए कि ऐप पृष्ठभूमि में जाता है या नहीं।
@Override
public void onActivityStopped(Activity activity) {
isActivityChangingConfigurations = activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// App enters background
}
}
यह काम किस प्रकार करता है:
यह एक छोटी सी चाल है जिस तरह से जीवनचक्र विधियों को अनुक्रम में कहा जाता है। मुझे एक परिदृश्य पर चलना चाहिए।
मान लें कि उपयोगकर्ता ऐप लॉन्च करता है और लॉन्चर गतिविधि ए लॉन्च की जाती है। जीवनचक्र कॉल होगा,
A.onCreate ()
एऑनस्टार्ट () (++ एक्टिविटी संदर्भ == 1) (ऐप फोरग्राउंड में प्रवेश करता है)
A.onResume ()
अब गतिविधि ए गतिविधि बी शुरू करती है।
A.onPause ()
B.onCreate ()
बी.स्टार्ट () (++ एक्टिविटी संदर्भ == 2)
B.onResume ()
ए। सोनटॉप () (- सक्रियता संदर्भ == 1)
तब उपयोगकर्ता गतिविधि बी से वापस नेविगेट करता है,
B.onPause ()
एऑनस्टार्ट () (++ एक्टिविटी संदर्भ == 2)
A.onResume ()
B.Stop () (- सक्रियता संदर्भ == 1)
B.onDestroy ()
तब उपयोगकर्ता होम बटन दबाता है,
A.onPause ()
एऑनटॉप () (- सक्रियता संदर्भ == 0) (ऐप पृष्ठभूमि में प्रवेश करता है)
मामले में, यदि उपयोगकर्ता बैक बटन के बजाय एक्टिविटी बी से होम बटन दबाता है, तब भी यह समान होगा और एक्टिविटी रीफ्रेंस होगी 0
। इसलिए, हम पृष्ठभूमि में प्रवेश करने वाले ऐप के रूप में पता लगा सकते हैं।
तो, क्या भूमिका है isActivityChangingConfigurations
? उपरोक्त परिदृश्य में, मान लीजिए कि गतिविधि बी अभिविन्यास को बदल देती है। कॉलबैक अनुक्रम होगा,
B.onPause ()
B.Stop () (--activityReferences == 0) (ऐप पृष्ठभूमि में प्रवेश करता है ??)
B.onDestroy ()
B.onCreate ()
B.StStart () (++ activityReferences == 1) (ऐप फ़ोरग्राउंड में प्रवेश करता है ?? ??
B.onResume ()
इसीलिए जब हम isActivityChangingConfigurations
कॉन्फ़िगरेशन परिवर्तन से गुजर रहे हैं तो परिदृश्य से बचने के लिए हमारे पास एक अतिरिक्त चेक है ।
मुझे पता लगाने के लिए एक अच्छी विधि मिली कि क्या अग्रभूमि या पृष्ठभूमि दर्ज करें। यहाँ मेरा कोड है । आशा है कि यह आपकी मदद करेगा।
/**
* 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();
}
संपादित करें 2: मैंने जो लिखा है वह वास्तव में काम नहीं करेगा। Google ने एक ऐप को अस्वीकार कर दिया है जिसमें ActivManager.getRunningTasks () के लिए एक कॉल शामिल है। से प्रलेखन , यह स्पष्ट है कि इस एपीआई डिबगिंग और विकास प्रयोजनों के लिए ही है। जैसे ही मेरे पास टाइम-टाइम का उपयोग करने वाली नई स्कीम के साथ GitHub प्रोजेक्ट को अपडेट करने का समय है, मैं इस पोस्ट को अपडेट करता रहूंगा और लगभग अच्छा भी हूं।
संपादन 1: मैंने एक ब्लॉग पोस्ट लिखी है और इसे वास्तव में आसान बनाने के लिए एक सरल GitHub रिपॉजिटरी बनाई है ।
स्वीकृत और शीर्ष रेटेड उत्तर दोनों वास्तव में सर्वोत्तम दृष्टिकोण नहीं हैं। IsApplicationBroughtToBackground () का शीर्ष रेटेड उत्तर का कार्यान्वयन उस स्थिति को नहीं संभालता है जहां एप्लिकेशन की मुख्य गतिविधि एक ही एप्लिकेशन में परिभाषित एक गतिविधि के लिए उपज है, लेकिन इसमें एक अलग जावा पैकेज है। मैं ऐसा करने का एक तरीका लेकर आया हूं जो उस मामले में काम करेगा।
इसे ऑनपॉज़ () में कॉल करें, और यह आपको बताएगा कि क्या आपका एप्लिकेशन बैकग्राउंड में जा रहा है क्योंकि कोई अन्य एप्लिकेशन शुरू हो गया है, या उपयोगकर्ता ने होम बटन दबाया है।
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;
}
यहाँ सही उत्तर
नीचे की तरह MyApp नाम से क्लास बनाएं:
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() {
}
}
फिर, हर जगह आप चाहते हैं (ऐप में लॉन्च की गई बेहतर पहली गतिविधि), नीचे दिए गए कोड को जोड़ें:
MyApp myApp = new MyApp();
registerComponentCallbacks(myApp);
getApplication().registerActivityLifecycleCallbacks(myApp);
किया हुआ! अब जब ऐप बैकग्राउंड में होता है, तो हमें लॉग मिलता है status : we are out
और जब हम ऐप में जाते हैं, तो हमें लॉग मिलता हैstatus : we are out
मेरा समाधान @ d60402 के उत्तर से प्रेरित था और एक समय-खिड़की पर भी निर्भर करता है, लेकिन इसका उपयोग नहीं कर रहा है 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();
}
}
जहां वर्ग का SingletonApplication
विस्तार है Application
:
public class SingletonApplication extends Application {
public boolean isInBackground = false;
public long lastForegroundTransition = 0;
}
मैं Google Analytics EasyTracker के साथ इसका उपयोग कर रहा था, और इसने काम किया। यह करने के लिए बढ़ाया जा सकता है कि आप एक साधारण पूर्णांक का उपयोग क्या चाहते हैं।
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) {
}
});
}
}
मुझे इसकी थोड़ी देर पता है, लेकिन मुझे लगता है कि इन सभी जवाबों में कुछ समस्याएं हैं जबकि मैंने इसे नीचे पसंद किया है और यह सही काम करता है।
इस तरह एक गतिविधि जीवन चक्र कॉलबैक बनाएँ:
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) {
}
}
और इसे नीचे की तरह अपने आवेदन वर्ग में पंजीकृत करें:
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifeCycle());
}
यह एंड्रॉइड के सबसे जटिल प्रश्नों में से एक प्रतीत होता है क्योंकि (इस लेखन के रूप में) एंड्रॉइड में iOS समकक्ष applicationDidEnterBackground()
या applicationWillEnterForeground()
कॉलबैक नहीं है। मैंने एक AppState लाइब्रेरी का उपयोग किया था जिसे @jenzz द्वारा एक साथ रखा गया था ।
[AppState] RxJava पर आधारित एक सरल, प्रतिक्रियाशील एंड्रॉइड लाइब्रेरी है जो ऐप स्टेट परिवर्तनों पर नज़र रखता है। यह हर बार ग्राहकों को सूचित करता है कि ऐप पृष्ठभूमि में जाता है और अग्रभूमि में वापस आता है।
यह पता चला कि यह वही है जिसकी मुझे ज़रूरत थी, खासकर क्योंकि मेरे ऐप में कई गतिविधियाँ थीं इसलिए बस जाँच करना onStart()
या onStop()
किसी गतिविधि पर इसे काटना नहीं था।
पहले मैंने इन निर्भरताओं को जोड़ दिया:
dependencies {
compile 'com.jenzz.appstate:appstate:3.0.1'
compile 'com.jenzz.appstate:adapter-rxjava2:3.0.1'
}
तब इन पंक्तियों को अपने कोड में उपयुक्त स्थान पर जोड़ना एक साधारण बात थी:
//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;
}
}
});
आप कैसे अवलोकन के लिए सदस्यता लेते हैं, इसके आधार पर, आपको मेमोरी लीक से बचने के लिए इससे सदस्यता समाप्त करनी पड़ सकती है। फिर से जीथूब पेज पर अधिक जानकारी ।
यह @ d60402 के उत्तर का संशोधित संस्करण है: https://stackoverflow.com/a/15573121/4747587
वहां बताई गई हर बात करें। लेकिन Base Activity
हर गतिविधि के लिए एक माता-पिता के रूप में एक होने और बनाने के बजाय , onResume()
और onPause
नीचे दिए गए कार्य को करें:
अपने आवेदन वर्ग में, पंक्ति जोड़ें:
registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks कॉलबैक);
यह callback
सभी गतिविधियों के जीवन चक्र के तरीकों है और आप अब ओवरराइड कर सकते हैं onActivityResumed()
और onActivityPaused()
।
इस Gist पर एक नज़र डालें: https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b
आप इसे आसानी से ActivityLifecycleCallbacks
और ComponentCallbacks2
कुछ नीचे की मदद से प्राप्त कर सकते हैं।
AppLifeCycleHandler
ऊपर दिए गए इंटरफेस को लागू करने वाला एक वर्ग बनाएं ।
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();
}
}
अपनी कक्षा में, जो एपर्चर को अग्रभूमि और पृष्ठभूमि के बीच स्विच करने पर कॉलबैक प्राप्त Application
करने के AppLifeCycleCallback
लिए लागू करता है। नीचे जैसा कुछ।
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");
}
}
उम्मीद है की यह मदद करेगा।
EDIT एक विकल्प के रूप में अब आप जीवन चक्र जागरूक वास्तुकला घटक का उपयोग कर सकते हैं।
चूंकि मुझे कोई दृष्टिकोण नहीं मिला, जो समय टिकटों की जांच के बिना रोटेशन को भी संभालता है, मैंने सोचा कि मैं भी साझा करता हूं कि अब हम इसे अपने ऐप में कैसे करते हैं। इस उत्तर https://stackoverflow.com/a/42679191/5119746 का एकमात्र जोड़ यह है कि हम अभिविन्यास को भी ध्यान में रखते हैं।
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
फिर, कॉलबैक के लिए हमारे पास पहले रिज्यूम है:
// ActivityLifecycleCallbacks
override fun onActivityResumed(activity: Activity?) {
mResumed++
if (mAppIsInBackground) {
// !!! App came from background !!! Insert code
mAppIsInBackground = false
}
mOrientationWasChanged = false
}
और onActivityStontin:
override fun onActivityStopped(activity: Activity?) {
if (mResumed == mPaused && !mOrientationWasChanged) {
// !!! App moved to background !!! Insert code
mAppIsInBackground = true
}
और फिर, यहाँ इसके अलावा आता है: अभिविन्यास परिवर्तन के लिए जाँच:
override fun onConfigurationChanged(newConfig: Configuration) {
if (newConfig.orientation != mCurrentOrientation) {
mCurrentOrientation = newConfig.orientation
mOrientationWasChanged = true
}
super.onConfigurationChanged(newConfig)
}
बस। आशा है कि यह किसी की मदद करता है :)
हम इस समाधान का विस्तार कर सकते हैं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
}
}
अब हम इस LiveData की सदस्यता ले सकते हैं और आवश्यक घटनाओं को पकड़ सकते हैं। उदाहरण के लिए:
appForegroundStateLiveData.observeForever { state ->
when(state) {
AppForegroundStateLiveData.State.FOREGROUND -> { /* app move to foreground */ }
AppForegroundStateLiveData.State.BACKGROUND -> { /* app move to background */ }
}
}
ये उत्तर सही प्रतीत नहीं होते हैं। जब कोई अन्य गतिविधि प्रारंभ और समाप्त होती है, तो इन विधियों को भी कहा जाता है। आप क्या कर सकते हैं एक वैश्विक झंडा रख सकते हैं (हाँ, ग्लोबल्स खराब हैं :) और इसे हर बार सच करने के लिए सेट करें जब आप एक नई गतिविधि शुरू करते हैं। प्रत्येक गतिविधि के चालू में इसे गलत पर सेट करें। फिर, ऑनपॉज में आप इस झंडे की जांच करते हैं। यदि यह गलत है, तो आपका ऐप पृष्ठभूमि में जा रहा है, या यह मारा जा रहा है।