2011-06-01 14 views
12

पठनीयता के लिए, मैंने कोड उदाहरण पोस्ट किए हैं जो मेरे समाधान पहले संदर्भित करते हैं, और फिर मैंने संख्यात्मक सूची में अपने समाधान की व्याख्या सूचीबद्ध की।एंड्रॉइड: बिटमैप्स, मेमोरी उपयोग और स्केलिंग के बारे में प्रश्न

मैं थोड़ी देर के लिए इसके साथ संघर्ष कर रहा हूं। मैंने बहुत पढ़ा है, यहां प्रश्न पूछे हैं, और प्रयोग किया है; लेकिन एक सभ्य समाधान के साथ नहीं आया है। मुझे इनपुट धाराओं से विभिन्न आकार की छवियों को पढ़ने की ज़रूरत है, और उन्हें अपनी गुणवत्ता की बाधाओं के रूप में उच्च गुणवत्ता के साथ प्रदर्शित करने की आवश्यकता है। नीचे दिए गए विकल्प हैं, जिनमें से कोई भी मेरे लिए बहुत अच्छा प्रतीत नहीं होता है। किसी भी मदद या इनपुट की सराहना की जाएगी।

public class NativeTest extends Activity 
{ 
    @Override 
    public void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     double nativeUsage = Debug.getNativeHeapAllocatedSize(); 
     Log.i("memory", nativeUsage+""); 
    } 
} 


double getAvailableMemory() 
{ 
    //current heap size 
    double heapSize = Runtime.getRuntime().totalMemory(); 
    //amount available in heap 
    double heapRemaining = Runtime.getRuntime().freeMemory(); 
    double nativeUsage = Debug.getNativeHeapAllocatedSize(); 
    double memoryAvailable = Runtime.getRuntime().maxMemory() - (heapSize - heapRemaining) - nativeUsage; 
    return memoryAvailable; 
} 

Bitmap createImageTrialAndError(InputStream stream) 
{ 
    Bitmap image = null; 
    int dowsample = 1; 
    while(image == null) 
    { 
     try 
     {  
     Options opts = new Options(); 
     opts.inSampleSize = downsample; 
     image = BitmapFactory.decodeStream(imgStream, null, opts); 
     } 
     catch (OutOfMemoryError ome) 
     { 
      downsample = downsample * 2; 
      Log.i("out of mem", "try using: " + downsample); 
     } 
    } 

    return image; 
} 
  1. आदर्श समाधान यदि बिटमैप एक Bitmap.drawBitmap (InputStream ...) विधि पड़ा होगा। यह मुझे बिटमैप के लिए स्मृति आवंटित किए बिना इनपुटस्ट्रीम से आकर्षित करने की अनुमति देगा। हां, यह एक विकल्प नहीं है।
  2. उपलब्ध स्मृति के अनुसार बिटमैप स्केल करें। इसमें बिटमैप की चौड़ाई और ऊंचाई को पुनर्प्राप्त करना शामिल है, बाइटमैप की संख्या की गणना करने के लिए बिटमैप को width * height * 4 के रूप में आवश्यक स्मृति की गणना करना आवश्यक है, और फिर BitmapFactory.Options.inSampleSize जैसे कि बिटमैप उपलब्ध होने की तुलना में कम स्मृति का उपयोग करेगा। हालांकि, यह विकल्प विफल रहता है क्योंकि मैं उपलब्ध स्मृति की गणना करने के लिए एक दूरस्थ रूप से विश्वसनीय तरीका नहीं ढूंढ पाया है। नीचे उपलब्ध GetMemory() विधि ऐसा लगता है जैसे इसे काम करना चाहिए: यह उपलब्ध स्मृति को अधिकतम मेमोरी के रूप में गणना करता है - जावा ढेर में उपयोग की जाने वाली मेमोरी - देशी ढेर में उपयोग की जाने वाली मेमोरी।
    दुर्भाग्य से, यह सूत्र बहुत अविश्वसनीय परिणाम देता है। मुख्य रूप से क्योंकि Debug.getNativeHeapAllocatedSize() बिटमैप मेमोरी उपयोग का सटीक प्रतिनिधित्व प्रतीत नहीं होता है। इसकी गलतता का एक स्पष्ट उदाहरण नीचे मूलभूत गतिविधि है। मेरे सैमसंग गैलेक्सी टैबलेट पर, लॉग स्टेटमेंट आउटपुट किया गया है: 3759416.0। एक खाली गतिविधि के लिए मूल आवंटन के 3.75 एमबी, स्पष्ट रूप से बिटमैप स्केलिंग निर्धारित करने के लिए एक विश्वसनीय तरीका नहीं है।
  3. एक के स्केलिंग कारक से शुरू करें, और बिटमैप को प्रारंभ करने का प्रयास करें; यदि स्मृति के कारण प्रारंभिक विफल रहता है, तो स्केलिंग कारक को दोगुना करें और पुनः प्रयास करें; और सफल होने तक इस प्रक्रिया को दोहराएं। यह createBitmapTrialAndError() द्वारा सचित्र है। यह वास्तव में आश्चर्यजनक रूप से प्रभावी है और बहुत धीमी नहीं है। हालांकि, यह बहुत अवांछनीय है क्योंकि मैं अपने आवेदन में कहीं और सॉफ़्ट रेफरेंस का उपयोग करता हूं, और मेमोरी से बाहर निकलने से इन सॉफ़्ट रेफरेंस का संग्रह होता है, जिसका महत्वपूर्ण प्रदर्शन प्रभाव पड़ता है। शुरुआत में उचित स्केलिंग कारक को जानना अधिक वांछनीय होगा, जो इन सॉफ्ट रेफरेंस के अनावश्यक संग्रह से बच जाएगा।
  4. मेरा अंतिम समाधान थोड़ा संदिग्ध लगता है। असल में यह 2 & 3 को जोड़ती है, लेकिन Debug.getNativeAllocatedSize() का उपयोग नहीं करती है। इसके बजाए, मैं अपने खुद के बिटमैप मेमोरी आवंटन को ट्रैक करता हूं, जहां भी मैं बिटमैप्स आवंटित करता हूं और उनकी मेमोरी उपयोग को टैल करता हूं, और फिर रीसायकल के किसी भी बिटमैप्स के मेमोरी उपयोग को घटाता हूं। बिटमैप्स के लिए उचित स्केलिंग कारक की गणना करने के लिए, मैं getAvailableMemory() में देशी उपयोग के स्थान पर इस मान का उपयोग करता हूं। और यदि इस विधि का उपयोग करने में आउट ऑफ़ मेमोरी अपवाद होता है, तो मैं स्वीकार्य पैमाने की गणना करने के लिए समाधान 3 को फ़ॉलबैक तरीके के रूप में उपयोग करता हूं। इसके साथ स्पष्ट समस्या मेरे अपने मूल स्मृति उपयोग को ट्रैक करने की कोशिश करने की विशाल स्केचनेस है, लेकिन मेरे लिए, यह सबसे अच्छा समाधान प्रतीत होता है।
+0

विकल्प 4 क्या आप के साथ फंस रहे हो रहा है। मैंने एक बार में कुछ सौ बिटमैप्स लोड करने की कोशिश करने के साथ कुछ काम किया है और उन्हें गतिशील रूप से स्केल किया है कि वे वास्तव में स्क्रीन पर कितने बड़े होंगे। आपके मामले में, अपना सर्वश्रेष्ठ अनुमान + मेमोरी ट्रैकिंग का उपयोग करना एक अच्छा तरीका है। नोट: विकल्प 1 को अभी भी ऑब्जेक्ट के लिए स्मृति आवंटित करने की आवश्यकता होगी, इसलिए उस फ़ंक्शन के बारे में चिंता न करें जो मौजूदा नहीं है। – Haphazard

+1

आपका बिटमैप स्क्रीन आकार से बड़ा नहीं हो सकता है ताकि नमूना आकार में शुरू करने के लिए एक अच्छी जगह हो, आप पूर्ण बिटमैप आयामों को स्मृति में पढ़ने के बिना डीकोडइनबाउंड का उपयोग कर सकते हैं और फिर आप इसे नीचे नमूना में पढ़ सकते हैं। 3.0+ पर भी बिटमैप जावा ढेर पर संग्रहीत हैं और मूल स्मृति नहीं है। – smith324

+3

सभी को यह बताना है कि "getAvailableMemory()" नकारात्मक संख्याएं वापस कर सकता है। – Zammbi

उत्तर

0

एंड्रॉयड ढेर के समस्या यह है कि आप वास्तव में ढेर आप उपयोग कर सकते हैं की कितना पता नहीं है, है, क्योंकि किसी भी पृष्ठभूमि सेवा कर सकता है आप के लिए किसी भी समय बर्बाद सब कुछ पर, आप स्मृति की कमी का अतिक्रमण करता है, तो।

आप केवल एक बिटमैप को कैनवास का आकार क्यों नहीं रखते हैं जिसे आप हमेशा चित्रित करते हैं, और डाउनसमैप्ड बिटमैप्स का ढेर? फिर आप सभी छवियों को अपने कैनवास के मूल समाधान में प्रस्तुत कर सकते हैं, और हमेशा होने वाले किसी भी बदलाव के लिए अपने डाउनस्प्लेड बिटमैप्स को खींच सकते हैं।एक बार परिवर्तन खत्म होने के बाद, या यह स्पष्ट है कि कौन सी छवि सबसे महत्वपूर्ण है, उसे मूल संकल्प में कैनवास (डिस्क को फिर से एक्सेस करके) को दोबारा हटा दें।

0

विकल्पों का "inJustDecodeBounds" संपत्ति का उपयोग करना एक सरल और सीधा तरीका है। इस प्रॉपर्टी को आपके द्वारा बनाए गए ऑब्जेक्ट ऑब्जेक्ट के लिए सही पर सेट करें, फिर स्ट्रीम को डीकोड करना जारी रखें।

लौटाया गया बिटमैप शून्य हो जाएगा, जिसका मतलब है कि इसमें कोई स्मृति आवंटित नहीं है, लेकिन आप बिटमैप के आयामों को पढ़ सकते हैं और इस प्रकार इसका आकार निर्धारित कर सकते हैं और नमूना आकार अनुपात समायोजित कर सकते हैं।

बाद में जस्ट डिकोडबाउंड को गलत में रीसेट करें, अब तक आप स्केल डाउन फैक्टर को जानते हैं, इस प्रकार आवश्यक आकार का बिटमैप अब उत्पन्न किया जा सकता है।

उम्मीद है कि इससे मदद मिलती है।

1

सही दृष्टिकोण उस आकार के लिए डीकोड करना है जिसे आपको दिखाने की आवश्यकता है और ज़ूम में छवि को टाइल में सब्सक्राइब करना है।

वहाँ एक पुस्तकालय है कि वास्तव में यह क्या करना चाहिए है, यह बाहर की जाँच: https://github.com/davemorrissey/subsampling-scale-image-view

संबंधित मुद्दे