2013-02-03 66 views
6

में मेरे पास व्यूपेगर है जिसका उपयोग मैं ज़ूम करने योग्य छवियों को दिखाने के लिए करता हूं (ImageViewTouch का उपयोग करके)। मुझे इंटरनेट (http) से बड़े बिटमैप्स लोड करने की आवश्यकता है। बड़े पैमाने पर मेरा मतलब 2000x1000 है। छवियों को इतना बड़ा होना चाहिए, क्योंकि वे ज़ूम करने योग्य हैं और विवरण दिखाने की आवश्यकता है। सर्वर पर छवियां .jpg प्रारूप हैं, लेकिन यह समस्या नहीं है - मैं इसे बदल सकता हूं।ViewPager में ImageView में बड़े बिटमैप लोड हो रहा है - मेमोरी

मैं स्मृति के साथ जांच प्राप्त किए बिना ImageViewTouch (ImageView) में इतनी बड़ी छवियों को लोड करने का प्रबंधन कैसे कर सकता हूं?

अब तक मैं बस का उपयोग कर रहा यह (AsyncTask):

ImageView currentView; //ImageView where to place image loaded from Internet 
    String ImageUrl; //URL of image to load 

    protected Bitmap doInBackground(ArrayList... params) { 

      Bitmap bitmap; 
      InputStream in = null; 
      imageUrl = (String)params[0].get(1); 

      try{ 
       HttpClient httpclient = new DefaultHttpClient(); 
       HttpResponse response = httpclient.execute(new HttpGet(imageUrl)); 
       in = response.getEntity().getContent(); 
      } catch(Exception e){ 
       e.printStackTrace(); 
      } 
      try { 
       bitmapa = BitmapFactory.decodeStream(in); 
       in.close(); 
      } catch (IOException e1) { 
       e1.printStackTrace(); 
      } 

      return bitmap; 
     } 


     @Override 
     protected void onPostExecute(Bitmap bitmap) { 

      currentView.setImageBitmap(bitmap); 
     } 

और यह स्मृति के साथ कई समस्याओं का कारण:

E/dalvikvm-heap(369): 69560740-byte external allocation too large for this process. 
E/GraphicsJNI(369): VM won't let us allocate 69560740 bytes 

या

E/AndroidRuntime(369): java.lang.RuntimeException: An error occured while executing doInBackground() 
E/AndroidRuntime(369): at android.os.AsyncTask$3.done(AsyncTask.java:200) 
E/AndroidRuntime(369): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274) 
E/AndroidRuntime(369): at java.util.concurrent.FutureTask.setException(FutureTask.java:125) 
E/AndroidRuntime(369): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308) 
E/AndroidRuntime(369): at java.util.concurrent.FutureTask.run(FutureTask.java:138) 
E/AndroidRuntime(369): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088) 
E/AndroidRuntime(369): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581) 
E/AndroidRuntime(369): at java.lang.Thread.run(Thread.java:1019) 
E/AndroidRuntime(369): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget 
E/AndroidRuntime(369): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method) 
E/AndroidRuntime(369): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:470) 
E/AndroidRuntime(369): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:525) 
E/AndroidRuntime(369): at com.package.app.ImageDownloader.doInBackground(ImageDownloader.java:78) 
E/AndroidRuntime(369): at com.package.app.ImageDownloader.doInBackground(ImageDownloader.java:1) 
E/AndroidRuntime(369): at android.os.AsyncTask$2.call(AsyncTask.java:185) 
E/AndroidRuntime(369): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306) 
E/AndroidRuntime(369): ... 4 more 
+0

http: // stackoverflow। कॉम/ए/24135283/2 9 4884 – Fattie

उत्तर

2

क्या के संस्करण ओएस क्या आप इसका परीक्षण करते हैं? पिछले संस्करणों पर उपलब्ध ढेर स्थान बाद के संस्करणों की तुलना में बहुत कम है।

मैं इससे बचने के लिए गंभीरता से अपने बिटमैप को कम करने पर विचार करता हूं। यदि आप एक एमडीपीआई फोन के लिए 2000x1000 Bitmap डाउनलोड कर रहे हैं तो यह शायद एक बुरा विचार है।

मैं अपने आयामों के आधार पर एक विशिष्ट ImageView के लिए उपयुक्त छवि को लोड करने के तरीके के बारे में अधिक जानकारी के लिए this article पढ़ने की भी सिफारिश करता हूं।

अंत में, आप हमेशा एक finally ब्लॉक में एक InputStream बंद हो जाना चाहिए:

try { 
     bitmap = BitmapFactory.decodeStream(in); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally { 
     if (in != null) { in.close(); } 
    } 

वहाँ भी android:largeHeap="true" जो आप विचार कर सकते हैं विशेष रूप से है कि इस तरह तस्वीर संपादन क्षुधा के रूप में बड़े बिटमैप्स, से निपटने के क्षुधा के लिए किया जाता है।

+0

उत्तर के लिए धन्यवाद। मेरा लक्ष्य एसडीके संस्करण 15 है और न्यूनतम 4 है। मैंने पहले से ही उस लेख को पढ़ लिया है लेकिन इससे मेरी मदद नहीं हुई - समस्या यह है कि मैं अपनी छवि का आकार बदल या स्केल नहीं कर सकता, क्योंकि इसे ज़ूम करने योग्य होना चाहिए और विवरण दिखाएं जूम। – michalsol

+0

मैं आपसे झूठ नहीं बोलूंगा, आपको स्मृति में 2000x1000 छवि फिट करने के लिए एक संभावित उत्तर नहीं मिलेगा। इसके बारे में सोचें, इससे कोई फर्क नहीं पड़ता कि आप उपलब्ध हेपस्पेस से अधिक हो जाएंगे।शायद आप क्रोम वेब ब्राउज़र कैसे काम करता है, इस तरह की एक अलग रणनीति मिल सकती है, स्मृति में छवि का केवल एक हिस्सा प्रस्तुत करें, क्योंकि उपयोगकर्ता आपके आस-पास पैन करता है, वर्तमान व्यूपोर्ट के आधार पर एक नई विंडो को तुरंत लोड करता है। – dnkoutso

+0

मैंने इसके बारे में सोचा - छवि के ज़ूम किए गए हिस्से को पुनः लोड करना - लेकिन इसे लागू करना काफी कठिन लगता है। क्या आपके पास इसका कोई ट्यूटोरियल है? धन्यवाद! – michalsol

2

एक 2000x1000 पिक्सेल छवि बड़ी है, लेकिन यह बड़ी नहीं है।

मैं देखता हूं, हालांकि यह प्रक्रिया मरने से पहले 69560740 बाइट आवंटित करने की कोशिश कर रही है, यह लगभग 66 एमबीईटी है!

आपके 2000x1000, सबसे बुरे मामले में, लगभग 2000x1000x4 = 8MBytes है, 6666ytes से कम तरीका है। कुछ और चल रहा है।

इसके अलावा, मुझे AsyncTasks में रिटर्न/परिणाम मान के रूप में बिटमैप्स का उपयोग करने में कोई समस्या मिली। AsyncTasks जो अभी भी समाप्त हो गए हैं, जब तक वे कचरा इकट्ठा नहीं हो जाते हैं। चूंकि आप AsyncTask उदाहरणों के गर्वर्ज संग्रह को नियंत्रित नहीं करते हैं, इसलिए बिटमैप को रिटर्न/परिणाम मान के रूप में उपयोग न करें। इसके बजाय शून्य पर एक क्षेत्र में बिटमैप रखा है और उसे आवंटित जब doInBackground समाप्त करने के लिए के बारे में है, और इस क्षेत्र का उपयोग onPostExecute और में बिटमैप प्राप्त करने के लिए सेट इस क्षेत्र (!):

Bitmap bitmap; 
protected Void doInBackground(ArrayList... params) { 

     InputStream in = null; 
     imageUrl = (String)params[0].get(1); 

     try{ 
      HttpClient httpclient = new DefaultHttpClient(); 
      HttpResponse response = httpclient.execute(new HttpGet(imageUrl)); 
      in = response.getEntity().getContent(); 
     } catch(Exception e){ 
      e.printStackTrace(); 
     } 
     try { 
      bitmap = BitmapFactory.decodeStream(in); 
      in.close(); 
     } catch (IOException e1) { 
      e1.printStackTrace(); 
     } 

     return null; 
    } 


    @Override 
    protected void onPostExecute(Void unused) { 
     if (bitmap != null) { 
      currentView.setImageBitmap(bitmap); 
     } 

     // And don't forget to null the bitmap field! 
     bitmap = null; 
    } 
+0

मेरे पिछले उत्तर में एक अतिरिक्त टिप्पणी के रूप में। मुझे लगता है कि आपका सर्वर बहुत बड़ी छवियां देता है, क्योंकि वीएम 69,500,000 बाइट आवंटित करने का प्रयास करता है। यह लगभग 3000x3000 पिक्सल की एक ARGB_8888 छवि होगी। –

+0

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