43

मैं हाल ही में Managing Your App's Memory पर इस लेख पढ़ा है, मैं दृढ़ता से इसे पढ़ने के लिए सुझाव है कि अगर आप एक AndroidDev कर रहे हैं और किया ही नहीं।समझ onTrimMemory (पूर्णांक स्तर)

और अच्छी प्रथाओं के बहुत सारे एक बात मैं जानना चाहता हूँ/टुकड़ा किसी घटना के समय पर स्मृति या जारी किया जा सकता है चाहिए सूचित करने के लिए onTrimMemory(int level) विधि हर गतिविधि पर प्रणाली द्वारा कहा जाता है के बारे में कभी नहीं रहे हैं।

सूचना है कि आपकी ऐप TRIM_MEMORY_UI_HIDDEN साथ onTrimMemory() कॉलबैक केवल अपने ऐप प्रक्रिया के सभी UI घटक उपयोगकर्ता से छिपा बन प्राप्त करता है:

यहाँ उस लेख से एक उद्धरण है। यह ऑनस्टॉप() कॉलबैक से अलग है, जिसे एक गतिविधि उदाहरण छुपाया जाता है, जो तब भी होता है जब उपयोगकर्ता में आपके ऐप में दूसरी गतिविधि में जाता है। इसलिए हालांकि आप onStop को लागू करना चाहिए() इस तरह के एक नेटवर्क कनेक्शन के रूप में गतिविधि संसाधनों को रिहा करने या प्रसारण रिसीवर, पंजीकरण रद्द करना जब तक आप onTrimMemory (TRIM_MEMORY_UI_HIDDEN) प्राप्त आप आमतौर पर अपने यूआई संसाधनों जारी नहीं करना चाहिए। यह सुनिश्चित करता है कि यदि उपयोगकर्ता आपके ऐप में किसी अन्य गतिविधि से वापस निकलता है, तो आपके यूआई संसाधन अभी भी गतिविधि को फिर से शुरू करने के लिए उपलब्ध हैं।

मैं वास्तव में अपने आवेदन में एक अच्छा स्मृति प्रबंधन को लागू तो मैं आगे देख रहा हूँ सही तरीके से लागू करने के लिए onTrimMemory() में दिलचस्पी है।

मैं केवल यह के बारे में कुछ प्रश्न हैं:

  • सही onStop के बाद onTrimMemory(TRIM_MEMORY_UI_HIDDEN) है कहा जाता है()?

  • उस संदर्भ में "आपके यूआई संसाधनों को जारी करने" का अर्थ क्या है? उदाहरण के लिए बिटमैप कैश साफ़ करें, या वास्तव में व्यू पेड़ में प्रत्येक दृश्य को हटा दें और नष्ट करें? मैं आमतौर पर पर डेस्ट्रॉय() या ऑनडेस्ट्रोव्यू() विधियों में दृश्यों को नष्ट कर देता हूं, अब मैं सोच रहा हूं कि मैं इसे सही कर रहा हूं या नहीं।

  • क्या onTrimMemory(TRIM_MEMORY_UI_HIDDEN) पर एक ट्विन/संवाददाता कॉलबैक है? जैसे onCreate-OnDestroy, onStart-onStop, onCreateView-onDestroyView। मैं यह समझने के लिए कह रहा हूं कि onTrimMemory(TRIM_MEMORY_UI_HIDDEN) के बाद अग्रभूमि में लाए गए गतिविधि/टुकड़े के बाद यूआई राज्य को कैसे और कैसे पुनर्स्थापित करना चाहिए। TRIM_MEMORY_UI_HIDDEN स्तर के साथ

+0

ध्यान दें कि ऑन एंड्रॉइड घटकों पर सिस्टम द्वारा ट्रिम मेमरी (स्तर) को सिस्टम द्वारा बुलाया जाता है - न केवल गतिविधि/टुकड़ा। – Tom

+0

यहां नमूना कार्यान्वयन देखें http://stackoverflow.com/a/28210326/185022 –

उत्तर

23
  • onTrimMemory वास्तव में onStop से पहले कहा जाता है। जब ऑनटॉप को कॉल किया जाता है, तो इसका मतलब है कि गतिविधि वास्तव में रोक रही है, और अगर एंड्रॉइड ओएस इसे तुरंत मार सकता है, तो आपको उस गतिविधि के कॉलबैक के लिए और भी कॉल की उम्मीद नहीं करनी चाहिए, इसके अलावा, रीस्टार्ट और कभी-कभी डेस्ट्रॉय को छोड़कर।

  • "अपने यूआई संसाधन जारी करें" वास्तव में कैश जैसी चीजों के बारे में है।आपको आमतौर पर विचारों या यूआई घटकों के प्रबंधन के बारे में चिंता करने की ज़रूरत नहीं है क्योंकि ओएस पहले से ही ऐसा करता है, और यही कारण है कि एक गतिविधि बनाने, शुरू करने, रोकने, रोकने और नष्ट करने के लिए उन सभी कॉलबैक हैं। हालांकि, कभी-कभी प्रदर्शन में सुधार करने के लिए आपको स्मृति उपयोग में वृद्धि करना पड़ता है, जैसे कि आपकी गतिविधियों द्वारा उपयोग किए जाने वाले कुछ डेटा कैशिंग करना। उस प्रकार का संसाधन है जिसे आपको रिलीज करना चाहिए जब TrimMemory को कॉल किया जाता है, इसलिए आपका ऐप कम मेमोरी का उपयोग करता है, भले ही यह प्रदर्शन को प्रभावित करता हो। हालांकि आपको मेमोरी लीक के बारे में चिंता करनी चाहिए। यदि आपकी गतिविधि बंद हो जाती है, तो सुनिश्चित करें कि इसके विचारों के संदर्भ में कोई संदर्भ न रखें, क्योंकि यह गतिविधि को कचरा इकट्ठा करने से रोकती है, जो पूरे संदर्भ को एकत्र होने से रोकती है, और यह बुरा है, अधिकतर यदि आप अपना ऐप चलाना चाहते हैं घंटों या दिनों के लिए (जैसे कि जब आप सेवाओं को लागू करते हैं)।

  • नहीं, TrimMemory पर कोई संवाददाता कॉलबैक नहीं है। हालांकि, आपको एक की आवश्यकता नहीं है। जैसा कि मैंने पहले कहा था, यदि आप प्रदर्शन को बेहतर बनाने के लिए कुछ संसाधनों का कैश रखते हैं, तो बस इसे खाली करें, और यदि इसे आवश्यकता हो तो इसे फिर से बढ़ने दें। यदि मेमोरी लेवल कम रहता है, तो उसी स्मृति स्तर के साथ, ट्रीममोरी को जल्द ही फिर से बुलाया जा सकता है। वैसे, ध्यान रखें कि TrimMemory को कई अलग-अलग मेमोरी स्तरों के साथ बुलाया जाएगा, न केवल TRIM_MEMORY_UI_HIDDEN।

+0

क्या आप समझा सकते हैं कि 'यदि आपकी गतिविधि बंद हो जाती है, तो सुनिश्चित करें कि इसके विचारों में कोई संदर्भ न रखें'? स्पष्टीकरण के लिए –

7

नमूना कार्यान्वयन

public class AppContext extends Application { 
//This my introduce OutOfMemoryException if you don't handle register and removal quiet well, better to replace it with weak reference 
private static List<IMemoryInfo> memInfoList = new ArrayList<AppContext.IMemoryInfo>(); 

public static abstract interface IMemoryInfo { 
     public void goodTimeToReleaseMemory(); 
    } 

@Override 
    public void onTrimMemory(int level) { 
     super.onTrimMemory(level); 
//don't compare with == as intermediate stages also can be reported, always better to check >= or <= 
      if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW) { 
       try { 
       // Activity at the front will get earliest than activity at the 
       // back 
       for (int i = memInfoList.size() - 1; i >= 0; i--) { 
        try { 
         memInfoList.get(i).goodTimeToReleaseMemory(); 
        } catch (Exception e) { 
         e.printStackTrace(); 
        } 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

/** 
    * 
    * @param implementor 
    *   interested listening in memory events 
    */ 
    public static void registerMemoryListener(IMemoryInfo implementor) { 
     memInfoList.add(implementor); 
    } 

    public static void unregisterMemoryListener(IMemoryInfo implementor) { 
     memInfoList.remove(implementor); 
    } 
} 

public class ActivityParent extends Activity implements AppContext.IMemoryInfo { 

    protected ActivityParent child; 


@Override 
    protected void onStop() { 
     super.onStop(); 
     try { 
      if (child != null) 
       AppContext.unregisterMemoryListener(child); 
     } catch (Exception e) { 

     } 
    } 
} 

public class ActivityChild extends ActivityParent { 
@Override 
    protected void onCreate(Bundle savedInstanceState) {   
     super.onCreate(savedInstanceState); 
     child = this; 
    } 

     /---move following onResume() in parent as following eg: 
/* 
*@Override 
*  protected void onResume() {  
*   super.onResume(); 
*   if(null != child){ 
*   AppContext.registerMemoryListener(this); 
*   } 
*  } 
*/ 
     @Override 
     protected void onResume() {  
      super.onResume(); 
      AppContext.registerMemoryListener(this); 
     } 

@Override 
public void goodTimeToReleaseMemory() { 
    super.goodTimeToReleaseMemory(); 
//remove your Cache etc here 
} 
//--NO Need because parent implementation will be called first, just for the sake of clarity 
@Override 
    protected void onStop() { 
     super.onStop(); 
     try { 
      if (null != child) 
       AppContext.unregisterMemoryListener(child); 
     } catch (Exception e) { 

     } 
    } 

अधिक जानकारी:

जब आपका ऐप चल रहा है: TRIM_MEMORY_RUNNING_MODERATE डिवाइस मेमोरी पर कम चलने शुरू हो रहा है। आपका ऐप चल रहा है और मारने योग्य नहीं है।

TRIM_MEMORY_RUNNING_LOW डिवाइस स्मृति पर बहुत कम चल रहा है। आपका ऐप चल रहा है और मारने योग्य नहीं है, लेकिन सिस्टम प्रदर्शन में सुधार करने के लिए अप्रयुक्त संसाधनों को छोड़ दें (जो आपके ऐप के प्रदर्शन को सीधे प्रभावित करता है)।

TRIM_MEMORY_RUNNING_CRITICAL डिवाइस स्मृति पर बहुत कम चल रहा है। आपके ऐप को अभी तक एक मारने योग्य प्रक्रिया नहीं माना गया है, लेकिन यदि सिस्टम संसाधनों को जारी नहीं करता है, तो सिस्टम पृष्ठभूमि प्रक्रियाओं को मारना शुरू कर देगा, इसलिए आपको प्रदर्शन में गिरावट को रोकने के लिए अब गैर-महत्वपूर्ण संसाधनों को जारी करना चाहिए।

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

जब आपके एप्लिकेशन की प्रक्रिया पृष्ठभूमि LRU सूची में रहता है: TRIM_MEMORY_BACKGROUND सिस्टम स्मृति कम हो रही है और अपने प्रक्रिया LRU सूची की शुरुआत के पास है। यद्यपि आपकी ऐप प्रक्रिया को मारने के उच्च जोखिम पर नहीं है, फिर भी सिस्टम LRU सूची में प्रक्रियाओं को मार रहा है, इसलिए आपको उन संसाधनों को छोड़ना चाहिए जो पुनर्प्राप्त करना आसान है, इसलिए आपकी प्रक्रिया सूची में रहेगी और उपयोगकर्ता के तुरंत बाद फिर से शुरू हो जाएगी आपके ऐप पर लौटता है।

TRIM_MEMORY_MODERATE सिस्टम स्मृति कम हो रही है और अपने प्रक्रिया LRU सूची के बीच के पास है। अगर प्रणाली स्मृति के लिए और बाध्य हो जाती है, तो एक मौका है कि आपकी प्रक्रिया मारे जायेगी।

TRIM_MEMORY_COMPLETE सिस्टम स्मृति कम हो रही है और अपने प्रक्रिया पहले से एक है, तो प्रणाली अब स्मृति की वसूली नहीं करता मारे जाने के लिए है। आपको अपनी ऐप स्थिति को फिर से शुरू करने के लिए बिल्कुल महत्वपूर्ण नहीं होना चाहिए। 14 से कम एपीआई स्तरों का समर्थन करने के लिए, आप onLowMemory() विधि का उपयोग फ़ॉलबैक के रूप में कर सकते हैं जो लगभग TRIM_MEMORY_COMPLETE स्तर के बराबर है।

http://developer.android.com/reference/android/content/ComponentCallbacks2.html

+1

धन्यवाद। यदि मैं गतिविधि में ट्रिममेमरी (इंट लेवल) पर उपयोग करता हूं, तो क्या यह स्वचालित रूप से कॉल हो जाएगा? –

1

मैं इस समस्या के लिए मजबूर किया गया था कि onTrimMemory() जब प्रदर्शन बंद कर दिया कभी नहीं बुलाया गया था। इस प्रकार मैं एक समाधान ActivityLifecycleCallbacks उपयोग करने की कोशिश:

onActivityStarted(){ 
    i++; 
} 

onActivityStopped(){ 
    i--; 
    if(i==0) // no more open activities, thus screen probably turned off 
} 

यह मेरे लिए काम किया लेकिन im यकीन नहीं है अगर यह एक सुरक्षित तरीका है: मैं एक साधारण काउंटर का इस्तेमाल किया। आरएफसी

अपडेट: कैमरा इरादा शुरू करना, एप्लिकेशन बंद भी है, इसलिए यह वांछित रूप से व्यवहार नहीं कर रहा है।

इसके बजाय इस कोड का उपयोग किया गया। ठीक काम करता है:

private void registerBroadcastReceiver() { 
    final IntentFilter theFilter = new IntentFilter(); 
    theFilter.addAction(Intent.ACTION_SCREEN_OFF); 

    BroadcastReceiver screenOnOffReceiver = new BroadcastReceiver() { 
     @Override 
     public void onReceive(Context context, Intent intent) { 
      String strAction = intent.getAction(); 
      if (strAction.equals(Intent.ACTION_SCREEN_OFF)) { 
       // do sth 
      } 
     } 
    }; 
    getApplicationContext() 
      .registerReceiver(screenOnOffReceiver, theFilter); 
} 
संबंधित मुद्दे