एंड्रॉइड ऐप पृष्ठभूमि पर जाने और अग्रभूमि में वापस आने पर कैसे पता लगाएं


382

मैं एक ऐसे ऐप को लिखने की कोशिश कर रहा हूं जो कुछ विशिष्ट करता है जब इसे कुछ समय के बाद अग्रभूमि में वापस लाया जाता है। क्या पता लगाने का कोई तरीका है कि किसी ऐप को बैकग्राउंड में भेजा जाए या अग्रभूमि में लाया जाए?


2
हो सकता है कि प्रश्न में उपयोग का मामला जोड़ा जाए क्योंकि यह स्पष्ट प्रतीत नहीं होता है, इसलिए इसे दिए गए उत्तरों में संबोधित नहीं किया गया है। ऐप एक और ऐप शुरू कर सकता है (उदाहरण के लिए गैलरी), जो अभी भी उसी स्टैक में रहेगा और ऐप की स्क्रीन में से एक के रूप में दिखाई देगा, और फिर होम बटन दबाएं। ऐप जीवनचक्र (या यहां तक ​​कि मेमोरी मैनेजमेंट) पर निर्भर तरीकों में से कोई भी इसका पता लगाने में सक्षम नहीं है। जब आप होम दबाते हैं, तो बाहरी गतिविधि दिखाई देने पर वे पृष्ठभूमि की स्थिति को ट्रिगर करेंगे।
डेनिस के

यह वह उत्तर है जिसकी आप तलाश कर रहे हैं: stackoverflow.com/a/42679191/2352699
फ्रेड पोर्सिनुकाला

1
Google समाधान देखें: stackoverflow.com/questions/3667022/…
user1269737

जवाबों:


98

onPause()और onResume()तरीकों जब आवेदन फिर पृष्ठभूमि करने के लिए और अग्रभूमि में लाया जाता है कहा जाता है। हालांकि, उन्हें तब भी बुलाया जाता है जब आवेदन पहली बार शुरू किया जाता है और इसे मारने से पहले। आप गतिविधि में अधिक पढ़ सकते हैं ।

पृष्ठभूमि या अग्रभूमि में आवेदन की स्थिति प्राप्त करने के लिए कोई प्रत्यक्ष दृष्टिकोण नहीं है, लेकिन यहां तक ​​कि मैंने इस मुद्दे का सामना किया है onWindowFocusChangedऔर इसके साथ समाधान पाया है onStop

अधिक जानकारी के लिए यहां Android की जांच करें : यह पता लगाने के लिए समाधान कि एंड्रॉइड ऐप कब बैकग्राउंड में जाता है और getRunningTasks या getRunningAppProcesses के बिना अग्रभूमि में वापस आ जाता है


173
हालाँकि यह दृष्टिकोण गलत सकारात्मकता का कारण बनता है क्योंकि अन्य लोगों ने बताया, क्योंकि इन तरीकों को उसी ऐप में गतिविधियों के बीच संक्रमण होने पर भी कहा जाता है।
जॉन लेहमैन

9
यह उससे भी बुरा है। मैंने इसे आजमाया और कभी-कभी onResume कहा जाता है जबकि फोन बंद है। यदि आप प्रलेखन में onResume की परिभाषा देखते हैं, तो आप पाएंगे: ध्यान रखें कि onResume सबसे अच्छा संकेतक नहीं है कि आपकी गतिविधि उपयोगकर्ता को दिखाई दे; सिस्टम विंडो जैसे कीगार्ड सामने हो सकता है। यह जानने के लिए onWindowFocusChanged (बूलियन) का उपयोग करें कि आपकी गतिविधि उपयोगकर्ता को दिखाई दे (उदाहरण के लिए, गेम को फिर से शुरू करने के लिए)। डेवलपर
.android.com/reference/android/app/…

2
लिंक में पोस्ट किया गया समाधान onResume / onPause का उपयोग नहीं करता है, इसके बजाय onBackPressed, onStop, onStart और onWindowsFocusChanged का संयोजन है। इसने मेरे लिए काम किया, और मेरे पास एक जटिल यूआई पदानुक्रम है (दराज, गतिशील
दर्शकों के

18
OnPause और onResume गतिविधि विशिष्ट हैं। आवेदन नहीं। जब किसी ऐप को बैकग्राउंड पर रखा जाता है और फिर से शुरू किया जाता है, तो यह बैकग्राउंड में जाने से पहले विशिष्ट गतिविधि को फिर से शुरू करता है। इसका मतलब यह है कि आपको अपने एप्लिकेशन की सभी गतिविधि में पृष्ठभूमि से फिर से शुरू करने पर जो कुछ भी करना है उसे लागू करने की आवश्यकता होगी। मेरा मानना ​​है कि मूल प्रश्न आवेदन और गतिविधि के लिए "onResume" जैसी किसी चीज़ की तलाश में था।
12

4
मैं विश्वास नहीं कर सकता कि इतनी सामान्य आवश्यकता के लिए एक उचित एपीआई की पेशकश नहीं की गई है। शुरू में मुझे लगा कि onUserLeaveHint () इसे काट देगा, लेकिन आप यह नहीं बता सकते हैं कि उपयोगकर्ता एप्लिकेशन छोड़ रहा है या नहीं
atsakiridis

197

2018: एंड्रॉइड इस मूल को जीवनचक्र के घटकों के माध्यम से समर्थन करता है।

मार्च 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कॉल बैक को निष्पादित करने की गारंटी नहीं है:

  1. यदि आपका फ़ोन स्क्रीन पर दिखाई देता है, जबकि आपका ऐप दिखाई देता है (जैसे कि nn मिनट के बाद आपका डिवाइस लॉक हो जाता है), इस कॉलबैक को (या हमेशा नहीं) कहा जाता है क्योंकि लॉकस्क्रीन अभी शीर्ष पर है, लेकिन आपका ऐप अभी भी "चल रहा है" यद्यपि कवर किया हुआ है।

  2. यदि आपका डिवाइस मेमोरी (और मेमोरी स्ट्रेस के तहत) पर अपेक्षाकृत कम है, तो ऑपरेटिंग सिस्टम इस कॉल को अनदेखा करता है और सीधे अधिक महत्वपूर्ण स्तरों पर जाता है।

अब, आपके लिए यह जानना कितना ज़रूरी है कि आपका ऐप कब बैकग्राउंड में चला गया है, आपको गतिविधि जीवनचक्र और व्हाट्सएप पर नज़र रखने के साथ इस समाधान का विस्तार करने की आवश्यकता हो सकती है या नहीं।

बस उपरोक्त को ध्यान में रखें और एक अच्छी क्यूए टीम है;)

अद्यतन का अंत

यह देर हो सकती है लेकिन आइसक्रीम सैंडविच (एपीआई 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);

और बस।


किसी सेवा से इसे चेक करते समय, होम बटन दबाने पर केवल आग लगती है। पीछे बटन दबाने से किटकैट पर यह आग नहीं लगती।
OpenGL ES

सेवा में कोई UI नहीं है इसलिए यह उससे संबंधित हो सकता है। अपनी आधार गतिविधि में जाँच करें, सेवा पर नहीं। आप यह जानना चाहते हैं कि आपका UI कब छिपा हुआ है (और शायद सेवा को बता दें, तो यह
फ़ोरग्राउंड

1
जब आप अपना फोन बंद करते हैं तो यह काम नहीं करता है। यह ट्रिगर नहीं है।
Juangcg

2
ComponentCallbacks2.onTrimMemory () (ActivityLifecycleCallbacks के संयोजन में) का उपयोग करना एकमात्र विश्वसनीय समाधान है जो मैंने अब तक पाया है, धन्यवाद मार्टिन! रुचि रखने वालों के लिए, मेरा प्रदान किया गया उत्तर देखें।
रिकुल

3
मैं एक साल पहले से इस पद्धति का उपयोग कर रहा हूं और यह हमेशा मेरे लिए विश्वसनीय रहा है। यह जानना अच्छा है कि अन्य लोग भी इसका उपयोग करते हैं। मैं केवल level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDENआपके अपडेट में समस्या से बचने के लिए उपयोग करता हूं , बिंदु 2। बिंदु 1 के बारे में, यह मेरे लिए चिंता की बात नहीं है, क्योंकि ऐप वास्तव में पृष्ठभूमि पर नहीं गया है, इसलिए यह काम करने का तरीका है।
सोरियनिव

175

यहां बताया गया है कि मैं इसे कैसे हल कर पाया हूं। यह इस आधार पर काम करता है कि गतिविधि संक्रमणों के बीच एक समय संदर्भ का उपयोग करने से सबसे अधिक संभावना पर्याप्त साक्ष्य प्रदान करेगी कि एक ऐप "पृष्ठभूमि में" रहा है या नहीं।

सबसे पहले, मैंने एक 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 को सही पर सेट किया गया था ।


4
हाय d60402, आपका उत्तर वास्तव में उपयोगी है .. इस उत्तर के लिए बहुत बहुत धन्यवाद ... छोटी सी सूचना .. MyApplication का उल्लेख मैनिफ़ेस्ट फ़ाइल एप्लिकेशन टैग में करना चाहिए जैसे कि Android: name = "MyApplication", अन्यथा ऐप क्रैश हो जाता है ... बस मदद करने के लिए मेरे जैसा कोई
praveenb

2
महान प्रोग्रामर का निशान, सबसे जटिल समस्या का एक सरल समाधान, जो मैं कभी आया था।
आशीष भटनागर 16

2
बहुत बढ़िया समाधान! धन्यवाद। अगर किसी को "ClassCastException" त्रुटि मिलती है, तो आप इसे अपने मेनिफेस्ट.एक्सएमएल <एप्लीकेशन एंड्रॉइड: name = "your.package.MyApplication" के अंदर एप्लिकेशन टैग में जोड़ने से चूक गए होंगे
उल हक

27
यह एक अच्छा और सरल कार्यान्वयन है। हालांकि मेरा मानना ​​है कि इसे ऑनस्टार्ट / ऑनस्पोर्ट के बजाय ऑनस्टार्ट / ऑनस्पॉट में लागू किया जाना चाहिए। यदि मैं एक संवाद शुरू करता हूं, जो गतिविधि को आंशिक रूप से कवर करता है, तब भी ऑनपॉज को बुलाया जाएगा। और संवाद को बंद करने से वास्तव में फोन होगा। ऐसा प्रतीत होता है जैसे कि ऐप अभी-अभी सामने आया है
शुभे

7
मैं इस समाधान के एक बदलाव का उपयोग करने की उम्मीद कर रहा हूं। ऊपर दिए गए संवादों के बारे में बात मेरे लिए एक समस्या है, इसलिए मैंने @ शुभायु के सुझाव (onStart / onStop) की कोशिश की। हालांकि मदद नहीं करता है क्योंकि A-> B, गतिविधि B के ऑनस्टार्ट () में जाने से पहले गतिविधि A के onStop () से पहले कॉल किया जाता है।
ट्रेवर

150

संपादित करें: नए आर्किटेक्चर घटक कुछ आशाजनक लाए हैं: ProcessLifecycleOwner , @ vokilam का उत्तर देखें


Google I / O टॉक के अनुसार वास्तविक समाधान :

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

}

हाँ। मुझे पता है कि इस सरल समाधान कार्यों पर विश्वास करना मुश्किल है क्योंकि हमारे पास यहां बहुत सारे अजीब समाधान हैं।

लेकिन उम्मीद है।


3
यह पूरी तरह से काम करता है! मैंने पहले से ही बहुत सारे अजीब समाधानों की कोशिश की जिसमें बहुत सारी खामियां थीं ... बहुत धन्यवाद! मैं थोड़ी देर के लिए यह देख रहा था।
एगाकिन बेकनवल्कर 12

7
यह कई गतिविधियों के लिए काम करता है, लेकिन एक के लिए - onrotate सभी गतिविधियों के बारे में या पृष्ठभूमि में चला जाएगा के बारे में संकेत देगा
डेडफिश

2
@Shyri आप सही हैं, लेकिन इस समाधान का हिस्सा है, इसलिए चिंता करने की जरूरत है। अगर फायरबेस इस पर निर्भर करता है, तो मुझे लगता है कि मेरा औसत ऐप भी :) महान जवाब बीटीडब्ल्यू हो सकता है।
इलियटएम

3
@deadfish उत्तर के शीर्ष में दिए गए I / O के लिंक की जाँच करें। आप गतिविधि रोक के बीच समय अंतराल की जांच कर सकते हैं और यह निर्धारित करने के लिए शुरू कर सकते हैं कि क्या आप वास्तव में पृष्ठभूमि में गए थे या नहीं। यह वास्तव में एक शानदार समाधान है।
एलेक्स बर्दनिकोव

2
वहाँ एक जावा समाधान है? यह कोटलिन है।
गियाकोमो बारटोली

116

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"

10
ध्यान दें कि आपको जीवन चक्र निर्भरता implementation "android.arch.lifecycle:extensions:1.0.0"और annotationProcessor "android.arch.lifecycle:compiler:1.0.0"Google की रिपॉजिटरी (यानी google()) से जोड़ने की आवश्यकता है
सर कोड्सालॉट

1
इसने मेरे लिए बहुत अच्छा काम किया, धन्यवाद। मुझे एपि 'android.arch.lifecycle: एक्सटेंशन: 1.1.0' का उपयोग करना था, कार्यान्वयन के बजाय एंड्रॉइड निर्भरता को त्रुटि के कारण संकलन और रनटाइम क्लासपाथ के लिए अलग संस्करण है।
FSUWX2011 20

यह एक महान समाधान है क्योंकि यह गतिविधि संदर्भ की आवश्यकता के बिना मॉड्यूल में काम करता है!
अधिकतम

ऐप क्रैश होने पर यह काम नहीं कर रहा है। क्या इस समाधान के माध्यम से ऐप दुर्घटनाग्रस्त घटना को भी हल करने के लिए कोई उपाय है
तेजराज

महान समाधान। मेरा दिन बचाया।
सनी

69

मार्टीन मार्कोसिनिस उत्तर (धन्यवाद!) के आधार पर अंत में मुझे एक विश्वसनीय (और बहुत सरल) समाधान मिला।

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

    }

}

क्या आप दिखा सकते हैं कि आप किसी ऐप में इसका उपयोग कैसे करते हैं, क्या मैं इसे ऐप क्लास से या कहीं और कॉल करता हूं?
JPM

यह बिल्कुल सही है, धन्यवाद!! काम करता है अब तक की जांच में महान
aherrick

यह उदाहरण अगर अधूरा है। RegisterActivityLifecycleCallbacks क्या है?
नोमन

कक्षा android.app.Application में इसकी एक विधि
रिकुल

1
अच्छी तरह से किया गया +1 शीर्ष पर जाने के लिए, क्योंकि यह एकदम सही है, अन्य उत्तरों को न देखें, यह @reno उत्तर पर आधारित है, लेकिन वास्तविक उदाहरण के साथ
Stoycho Andreev

63

हम इस विधि का उपयोग करते हैं। यह काम करने के लिए बहुत सरल लगता है, लेकिन यह हमारे ऐप में अच्छी तरह से परीक्षण किया गया था और वास्तव में सभी मामलों में आश्चर्यजनक रूप से अच्छी तरह से काम करता है, जिसमें "होम" बटन द्वारा "रिटर्न" बटन, या स्क्रीन लॉक के बाद होम स्क्रीन पर जाना शामिल है। कोशिश करो।

आइडिया है, जब अग्रभूमि में, पिछले एक को रोकने से पहले एंड्रॉइड हमेशा नई गतिविधि शुरू करता है। यह गारंटी नहीं है, लेकिन यह है कि यह कैसे काम करता है। 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 () में चले गए। इसके अलावा, मैं सुपर कॉल्स जोड़ रहा हूं, जो मेरे शुरुआती पोस्ट से गायब थे, क्योंकि यह एक वर्किंग कोड की तुलना में अधिक अवधारणा थी।


2
यह सबसे विश्वसनीय जवाब है, हालांकि मैं onResume के बजाय onStart का उपयोग करता हूं।
ग्रेग एननिस

आपको ओवरराइड विधियों में super.onResume () और super.onStop () में कॉल जोड़ना चाहिए। अन्यथा एक android.app.SuperNotCalledException को फेंक दिया जाता है।
जनवरी को Jan Laussmann

1
मेरे लिए यह काम नहीं करता है ... या कम से कम यह घटना को आग लगाता है जब आप डिवाइस को घुमा रहे हैं (जो कि एक झूठी सकारात्मक इमो की तरह है)।
नोया

बहुत ही सरल और कारगर उपाय! लेकिन मुझे यकीन नहीं है कि यह आंशिक रूप से पारदर्शी गतिविधियों के साथ काम करता है जो पिछली गतिविधि के कुछ हिस्सों को दिखाई देते हैं। डॉक्स से, onStop is called when the activity is no longer visible to the user
निकोलस ब्यूक

3
यदि उपयोगकर्ता पहली गतिविधि पर अभिविन्यास बदलता है तो क्या होता है? यह रिपोर्ट करेगा कि ऐप बैकग्राउंड में गया था जो कि सच नहीं है। आप इस परिदृश्य को कैसे संभालेंगे?
निमरोड दयाण

54

यदि आपके ऐप में एक टैब बार विजेट की तरह कई एक्टिविटीज़ और / या स्टैक्ड एक्टीविटीज़ हैं, तो ऑनपॉज़ () और ऑनस्क्यूम () काम नहीं करेगा। एक नई गतिविधि शुरू करने के बाद यानी वर्तमान गतिविधियों को नया बनाने से पहले रोक दिया जाएगा। जब एक गतिविधि "बैक" बटन का उपयोग कर खत्म होती है तो वही लागू होता है।

मुझे दो तरीके मिले हैं जो काम करना चाहते हैं।

पहले वाले को 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 तक पहुँच जाती है, तो आवेदन को पृष्ठभूमि में रखा जाता है यदि निम्न स्थितियाँ सत्य हैं:

  • गतिविधि को रोका जा रहा है समाप्त नहीं किया जा रहा है ("बैक" बटन का उपयोग किया गया था)। यह विधि activity.isFinishing () का उपयोग करके किया जा सकता है
  • एक नई गतिविधि (समान पैकेज नाम) शुरू नहीं की जा रही है। आप एक चर को सेट करने के लिए startActivity () विधि को ओवरराइड कर सकते हैं जो इसे इंगित करता है और फिर इसे onPostResume () में रीसेट कर देता है, जो एक गतिविधि बनने / फिर से शुरू होने पर चलाने की अंतिम विधि है।

जब आप यह पता लगा सकते हैं कि एप्लिकेशन ने पृष्ठभूमि से इस्तीफा दे दिया है, तो यह आसानी से पता लगाया जाता है कि कब इसे वापस अग्रभूमि में लाया जाए।


18
Google संभवतः एक ऐप को अस्वीकार कर देगा जो ActivManager.getRunningTasks () का उपयोग करता है। प्रलेखन में कहा गया है कि यह केवल शत्रु है। डेवलपर
स्काई केल्से


1
मैंने पाया कि मुझे इन तरीकों के संयोजन का उपयोग करना था। onUserLeaveHint () को 14. में एक गतिविधि शुरू करते समय बुलाया गया था। `@Override public void onUserLeaveHint () {inBackground = isApplicationBroughtToBackground (); } `
लिस्टिंग नाव

7
उपयोगकर्ता एक शक्तिशाली अनुमति android.permission.GET_TASKS का उपयोग करने के बारे में बहुत खुश नहीं होंगे।
MSquare

6
getRunningTasks एपीआई स्तर में हटा दिया गया है 21
Noya

33

एक क्लास बनाएं जो फैली हुई हो 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
        }
    }

1
के लिए FragmentActivityआप भी जोड़ सकते हैं level == ComponentCallbacks2.TRIM_MEMORY_COMPLETEभी।
सर्जन सिम्हा

2
इस विधि को इंगित करने के लिए बहुत बहुत धन्यवाद, मुझे पिन डायलॉग दिखाने की आवश्यकता है जब भी उपयोगकर्ता पृष्ठभूमि के लिए गतिविधि को फिर से शुरू करता है, तो इस विधि का उपयोग प्रीफ वैल्यू लिखने के लिए किया जाता है और आधार मूल्य पर इस मान की जांच की जाती है।
सैम

18

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

19
onUserLeaveHint को किसी अन्य गतिविधि के लिए नेविगेट करते समय भी कहा जाता है
जोनास स्टॉस्की

3
onUserLeaveHint को तब नहीं बुलाया जाता है जब कोई फ़ोन कॉल आता है और कॉलिंग गतिविधि सक्रिय हो जाती है, इसलिए इसमें एक किनारे वाला मामला भी है - ऐसे अन्य मामले भी हो सकते हैं, क्योंकि आप onUserLeaveHint कॉल को दबाने के इरादे से एक ध्वज जोड़ सकते हैं। डेवलपर
.android.com

1
इसके अलावा, onResume अच्छी तरह से काम नहीं करता है। मैंने इसे आज़माया और कभी-कभी onResume कहा जाता है जबकि फोन बंद है। यदि आप प्रलेखन में onResume की परिभाषा देखते हैं, तो आप पाएंगे: ध्यान रखें कि onResume सबसे अच्छा संकेतक नहीं है कि आपकी गतिविधि उपयोगकर्ता को दिखाई दे; सिस्टम विंडो जैसे कीगार्ड सामने हो सकता है। यह जानने के लिए कि आपकी गतिविधि उपयोगकर्ता को दिखाई दे रही है (उदाहरण के लिए, गेम फिर से शुरू करने के लिए) onWindowFocusChanged (बूलियन) का उपयोग करें। डेवलपर
.android.com/reference/android/app/…

यह समाधान अग्रभूमि / पृष्ठभूमि को तय करने में मदद नहीं करता है यदि कई गतिविधियाँ हैं। कृपया संदर्भ देखें stackoverflow.com/questions/3667022/…
राज त्रिवेदी

14

एक्टिविटी लाइफ़साइकलकॉल ब्याज की हो सकती है, लेकिन यह अच्छी तरह से प्रलेखित नहीं है।

हालाँकि, यदि आप registerActivityLifecycleCallbacks () को कॉल करते हैं, तो जब आप गतिविधियाँ बनते हैं, नष्ट हो जाते हैं, आदि के लिए आपको कॉलबैक प्राप्त करने में सक्षम होना चाहिए। आप गतिविधि के लिए getComponentName () कॉल कर सकते हैं ।


11
एपीआई स्तर 14 = \ के बाद से
imort

ऐसा लगता है कि यह साफ है और मेरे लिए काम करता है। धन्यवाद
duanbo1983

यह स्वीकृत उत्तर से कैसे भिन्न है, दोनों एक ही गतिविधि जीवनचक्र पर निर्भर हैं?
सैतामा

13

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


और इसे प्रकट करने के लिए इस तरह जोड़ें: <application android: name = "। अन्य।">
Dan Alboteanu

9

अपने आवेदन में कॉलबैक जोड़ें और इस तरह से रूट गतिविधि के लिए जाँच करें:

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

मैं कार्यान्वयन के इस तरीके का उपयोग करने पर विचार करूंगा। एक गतिविधि से दूसरे में संक्रमण केवल कुछ मिलीसेकंड लेता है। उस समय के आधार पर जब अंतिम गतिविधि गायब हो जाती है, एक विशिष्ट रणनीति द्वारा उपयोगकर्ता को फिर से लॉगिन करने पर विचार किया जा सकता है।
drindt

6

मैंने जीथब ऐप-अग्रभूमि-पृष्ठभूमि-सुनो पर एक परियोजना बनाई है

अपने आवेदन में सभी गतिविधि के लिए एक बेसएक्टिविटी बनाएं।

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

अब इस बेसएक्टिविटी को अपनी सभी गतिविधि के एक सुपर क्लास के रूप में उपयोग करें जैसे कि मेनऐक्टिविटी बेसएक्टिविटी को बढ़ाती है और जब आप अपना एप्लिकेशन शुरू करते हैं तो ऑनएपस्टार्ट को बुलाया जाएगा और जब एप्लिकेशन किसी भी स्क्रीन पर बैकग्राउंड चला जाएगा तो ऑनपॉज़ () कहा जाएगा।


@किरण बोगरा: क्या आपके समाधान में कोई झूठी सकारात्मकता है?
हरीश विश्वकर्मा

इस मामले में सही उत्तर onStart () और onStop () फ़ंक्शन का उपयोग किया जा सकता है। जो आपको आपके ऐप के बारे में बताता है
पीर फहीम शाह

6

यह बहुत आसान है 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


5

आप 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आपके एप्लिकेशन की घटनाओं को कैप्चर कर पाएंगे ।


4

जब कोई संपूर्ण अनुप्रयोग पृष्ठभूमि / अग्रभूमि में जाता है, तो आपको बताने के लिए कोई सीधी जीवन पद्धति नहीं होती है।

मैंने इसे सरल तरीके से किया है। एप्लिकेशन पृष्ठभूमि / अग्रभूमि चरण का पता लगाने के लिए नीचे दिए गए निर्देशों का पालन करें।

थोड़ा वर्कअराउंड के साथ, यह संभव है। यहां, एक्टिविटी लाइफ़साइकल कॉलबैक बचाव में आता है। मुझे चरण-दर-चरण चलो।

  1. सबसे पहले, एक वर्ग है कि फैली बनाने android.app.Application और औजार ActivityLifecycleCallbacks इंटरफ़ेस। Application.onCreate () में, कॉलबैक रजिस्टर करें।

    public class App extends Application implements 
        Application.ActivityLifecycleCallbacks {
    
        @Override
        public void onCreate() {
            super.onCreate();
            registerActivityLifecycleCallbacks(this);
        }
    }
  2. नीचे के रूप में मैनिफेस्ट में "ऐप" क्लास रजिस्टर करें <application android:name=".App"

  3. शुरू की स्थिति में कम से कम एक गतिविधि तब होगी जब ऐप अग्रभूमि में हो और जब अनुप्रयोग पृष्ठभूमि में हो तो प्रारंभ की गई अवस्था में कोई गतिविधि नहीं होगी।

    "अनुप्रयोग" वर्ग में नीचे के रूप में 2 चर घोषित करें।

    private int activityReferences = 0;
    private boolean isActivityChangingConfigurations = false;

    activityReferencesशुरू राज्य में गतिविधियों की संख्या की गिनती रखेंगे । isActivityChangingConfigurationsयह इंगित करने के लिए एक ध्वज है कि क्या वर्तमान गतिविधि एक अभिविन्यास स्विच की तरह कॉन्फ़िगरेशन परिवर्तन से गुजर रही है।

  4. यदि एप्लिकेशन अग्रभूमि में आता है, तो निम्न कोड का उपयोग करके आप यह पता लगा सकते हैं।

    @Override
    public void onActivityStarted(Activity activity) {
        if (++activityReferences == 1 && !isActivityChangingConfigurations) {
            // App enters foreground
        }
    }
  5. यह पता लगाने के लिए कि ऐप पृष्ठभूमि में जाता है या नहीं।

    @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कॉन्फ़िगरेशन परिवर्तन से गुजर रहे हैं तो परिदृश्य से बचने के लिए हमारे पास एक अतिरिक्त चेक है ।


3

मुझे पता लगाने के लिए एक अच्छी विधि मिली कि क्या अग्रभूमि या पृष्ठभूमि दर्ज करें। यहाँ मेरा कोड है । आशा है कि यह आपकी मदद करेगा।

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

}


3

आप उपयोग कर सकते हैं:

संरक्षित शून्य onRestart ()

नई शुरुआत और पुनरारंभ के बीच अंतर करने के लिए।

यहां छवि विवरण दर्ज करें


3

संपादित करें 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;
}

FYI करें, इसे ऑनस्टार्ट () में कॉल करने से इसके बजाय यह कहा जाने से बच जाएगा जब एक साधारण संवाद को फेंक दिया जाता है, उदाहरण के लिए, एक अलार्म बंद हो रहा है।
स्काई केल्सी

2

यहाँ सही उत्तर

नीचे की तरह 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


1

मेरा समाधान @ 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;
}

1

मैं 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) {

            }
        });
    }
}

1

मुझे इसकी थोड़ी देर पता है, लेकिन मुझे लगता है कि इन सभी जवाबों में कुछ समस्याएं हैं जबकि मैंने इसे नीचे पसंद किया है और यह सही काम करता है।

इस तरह एक गतिविधि जीवन चक्र कॉलबैक बनाएँ:

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

यह प्रत्येक गतिविधि पर हर समय कहा जाता है। मैं इसका उपयोग कैसे कर सकता हूं यदि उदाहरण के लिए मैं उपयोगकर्ता ऑनलाइन स्थिति का पता लगाना चाहता हूं
मेक्सिम नियाज़ेव

सवाल क्या चाहता है। यह केवल तब कहा जाता है जब आप होम स्क्रीन पर जाते हैं और किसी भी गतिविधि पर लौटते हैं।
अमीर ज़ियारती

अगर आपको इंटरनेट कनेक्टिविटी से मतलब है तो मुझे लगता है कि इसकी जांच करना बेहतर है कि आपको कब इसकी आवश्यकता है। अगर आपको कॉल करने से ठीक पहले इंटरनेट कनेक्शन की जांच करने के लिए एपी की जरूरत है।
आमिर ज़ियारती

1

यह एंड्रॉइड के सबसे जटिल प्रश्नों में से एक प्रतीत होता है क्योंकि (इस लेखन के रूप में) एंड्रॉइड में 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;
        }
    }
});

आप कैसे अवलोकन के लिए सदस्यता लेते हैं, इसके आधार पर, आपको मेमोरी लीक से बचने के लिए इससे सदस्यता समाप्त करनी पड़ सकती है। फिर से जीथूब पेज पर अधिक जानकारी ।


1

यह @ d60402 के उत्तर का संशोधित संस्करण है: https://stackoverflow.com/a/15573121/4747587

वहां बताई गई हर बात करें। लेकिन Base Activityहर गतिविधि के लिए एक माता-पिता के रूप में एक होने और बनाने के बजाय , onResume()और onPauseनीचे दिए गए कार्य को करें:

अपने आवेदन वर्ग में, पंक्ति जोड़ें:

registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks कॉलबैक);

यह callbackसभी गतिविधियों के जीवन चक्र के तरीकों है और आप अब ओवरराइड कर सकते हैं onActivityResumed()और onActivityPaused()

इस Gist पर एक नज़र डालें: https://gist.github.com/thsaravana/1fa576b6af9fc8fff20acfb2ac79fa1b


1

आप इसे आसानी से 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 एक विकल्प के रूप में अब आप जीवन चक्र जागरूक वास्तुकला घटक का उपयोग कर सकते हैं।


1

चूंकि मुझे कोई दृष्टिकोण नहीं मिला, जो समय टिकटों की जांच के बिना रोटेशन को भी संभालता है, मैंने सोचा कि मैं भी साझा करता हूं कि अब हम इसे अपने ऐप में कैसे करते हैं। इस उत्तर 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)
   }

बस। आशा है कि यह किसी की मदद करता है :)


1

हम इस समाधान का विस्तार कर सकते हैं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 */ }
    }
}

0

ये उत्तर सही प्रतीत नहीं होते हैं। जब कोई अन्य गतिविधि प्रारंभ और समाप्त होती है, तो इन विधियों को भी कहा जाता है। आप क्या कर सकते हैं एक वैश्विक झंडा रख सकते हैं (हाँ, ग्लोबल्स खराब हैं :) और इसे हर बार सच करने के लिए सेट करें जब आप एक नई गतिविधि शुरू करते हैं। प्रत्येक गतिविधि के चालू में इसे गलत पर सेट करें। फिर, ऑनपॉज में आप इस झंडे की जांच करते हैं। यदि यह गलत है, तो आपका ऐप पृष्ठभूमि में जा रहा है, या यह मारा जा रहा है।


मैंने डेटाबेस के बारे में बात नहीं की ... आपका क्या मतलब है?
जोरिस वीमर

मैं आपके उत्तर का समर्थन कर रहा हूँ। भले ही हम उस फ्लैग वैल्यू को डेटाबेस में सेव कर सकते हैं, जबकि पॉज़ कॉल पर यह अच्छा समाधान नहीं है ..
संदीप पी।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.