android - एक बिटमैप ऑब्जेक्ट में एक छवि लोड करते समय स्मृति समस्या से अजीब




image bitmap (20)

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

सूची दृश्य पर छवि पूर्वावलोकन कर्सर और ListAdapter साथ किया जा रहा है। यह बहुत आसान बनाता है, लेकिन मुझे यकीन नहीं है कि मैं एक आकार की छवि कैसे डाल सकता हूं (Ie छोटे आकार का आकार फ्लाई पर छवि बटन के लिए src रूप में पिक्सेल नहीं है। इसलिए मैंने फोन कैमरे से आने वाली छवि का आकार बदल दिया।

मुद्दा यह है कि जब मैं वापस जाने और दूसरी गतिविधि को दोबारा लॉन्च करने की कोशिश करता हूं तो मुझे स्मृति त्रुटि से बाहर निकलना पड़ता है।

  • क्या कोई तरीका है कि मैं सूची एडाप्टर को पंक्ति से आसानी से पंक्ति बना सकता हूं, जहां मैं फ्लाई ( बिट वार ) पर आकार बदल सकता हूं?

यह बेहतर होगा क्योंकि मुझे प्रत्येक पंक्ति में विजेट / तत्वों के गुणों में कुछ बदलाव करने की आवश्यकता है क्योंकि मैं फोकस समस्या के कारण टच स्क्रीन के साथ एक पंक्ति का चयन करने में असमर्थ हूं। ( मैं रोलर बॉल का उपयोग कर सकता हूं। )

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

जैसे ही मैंने सूची में छवि को अक्षम कर दिया, फिर भी यह ठीक काम करता था।

एफवाईआई: इस तरह मैं इसे कर रहा था:

String[] from = new String[] { DBHelper.KEY_BUSINESSNAME,DBHelper.KEY_ADDRESS,DBHelper.KEY_CITY,DBHelper.KEY_GPSLONG,DBHelper.KEY_GPSLAT,DBHelper.KEY_IMAGEFILENAME  + ""};
int[] to = new int[] {R.id.businessname,R.id.address,R.id.city,R.id.gpslong,R.id.gpslat,R.id.imagefilename };
notes = new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
setListAdapter(notes);

जहां R.id.imagefilename एक ButtonImage

मेरा लॉगकैट यहाँ है:

01-25 05:05:49.877: ERROR/dalvikvm-heap(3896): 6291456-byte external allocation too large for this process.
01-25 05:05:49.877: ERROR/(3896): VM wont let us allocate 6291456 bytes
01-25 05:05:49.877: ERROR/AndroidRuntime(3896): Uncaught handler: thread main exiting due to uncaught exception
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:304)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:149)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:174)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.graphics.drawable.Drawable.createFromPath(Drawable.java:729)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ImageView.resolveUri(ImageView.java:484)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ImageView.setImageURI(ImageView.java:281)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.SimpleCursorAdapter.setViewImage(SimpleCursorAdapter.java:183)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:129)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.CursorAdapter.getView(CursorAdapter.java:150)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.AbsListView.obtainView(AbsListView.java:1057)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.makeAndAddView(ListView.java:1616)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.fillSpecific(ListView.java:1177)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.ListView.layoutChildren(ListView.java:1454)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.AbsListView.onLayout(AbsListView.java:937)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1108)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.onLayout(LinearLayout.java:922)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:999)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.LinearLayout.onLayout(LinearLayout.java:920)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.ViewRoot.performTraversals(ViewRoot.java:771)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1103)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.os.Handler.dispatchMessage(Handler.java:88)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.os.Looper.loop(Looper.java:123)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at android.app.ActivityThread.main(ActivityThread.java:3742)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at java.lang.reflect.Method.invokeNative(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at java.lang.reflect.Method.invoke(Method.java:515)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896):     at dalvik.system.NativeStart.main(Native Method)
01-25 05:10:01.127: ERROR/AndroidRuntime(3943): ERROR: thread attach failed 

एक छवि प्रदर्शित करते समय भी मुझे एक नई त्रुटि है:

01-25 22:13:18.594: DEBUG/skia(4204): xxxxxxxxxxx jpeg error 20 Improper call to JPEG library in state %d
01-25 22:13:18.604: INFO/System.out(4204): resolveUri failed on bad bitmap uri: 
01-25 22:13:18.694: ERROR/dalvikvm-heap(4204): 6291456-byte external allocation too large for this process.
01-25 22:13:18.694: ERROR/(4204): VM won't let us allocate 6291456 bytes
01-25 22:13:18.694: DEBUG/skia(4204): xxxxxxxxxxxxxxxxxxxx allocPixelRef failed

OutOfMemory त्रुटि को ठीक करने के लिए, आपको ऐसा कुछ करना चाहिए:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap = BitmapFactory.decodeStream(is, null, options);

यह inSampleSize विकल्प स्मृति खपत को कम करता है।

यहां एक पूरी विधि है। सबसे पहले यह सामग्री को डीकोड किए बिना छवि आकार को पढ़ता है। फिर यह सबसे अच्छा inSampleSize मान पाता है, यह 2 की शक्ति होनी चाहिए, और आखिर में छवि डीकोड की गई है।

// Decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f) {
    try {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(f), null, o);

        // The new size we want to scale to
        final int REQUIRED_SIZE=70;

        // Find the correct scale value. It should be the power of 2.
        int scale = 1;
        while(o.outWidth / scale / 2 >= REQUIRED_SIZE && 
              o.outHeight / scale / 2 >= REQUIRED_SIZE) {
            scale *= 2;
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {}
    return null;
}

मुझे लगता है कि OutOfMemoryError से बचने का सबसे अच्छा तरीका इसका सामना करना और समझना है।

मैंने जानबूझकर OutOfMemoryError कारण बनने के लिए एक app बनाया, और मेमोरी उपयोग की निगरानी की।

इस ऐप के साथ मैंने कई प्रयोग किए हैं, मुझे निम्नलिखित निष्कर्ष मिल गए हैं:

मैं पहले हनी कंघी से पहले एसडीके संस्करणों के बारे में बात करने जा रहा हूं।

  1. बिटमैप देशी ढेर में संग्रहीत है, लेकिन इसे स्वचालित रूप से एकत्रित कचरा मिलेगा, रीसायकल () को कॉल करना आवश्यक नहीं है।

  2. यदि {वीएम ढेर आकार} + {आवंटित देशी ढेर मेमोरी}> = {डिवाइस के लिए वीएम ढेर आकार सीमा}, और आप बिटमैप बनाने की कोशिश कर रहे हैं, ओओएम फेंक दिया जाएगा।

    नोटिस: वीएम हेप आकार की गणना वीएम आवंटित स्मृति के बजाय की जाती है।

  3. वीएम हीप का आकार उगाए जाने के बाद कभी भी कम नहीं होगा, भले ही आवंटित वीएम मेमोरी कम हो जाए।

  4. तो आपको बिट वीएपी मेमोरी को बिटमैप्स के लिए उपलब्ध मेमोरी को बचाने के लिए वीएम हीप आकार को बहुत बड़ा होने से रोकने के लिए जितना संभव हो उतना कम रखना होगा।

  5. मैन्युअल रूप से System.gc () को कॉल करें अर्थहीन है, सिस्टम ढेर आकार को बढ़ाने की कोशिश करने से पहले इसे पहले कॉल करेगा।

  6. मूल ढेर का आकार कभी भी कम नहीं होगा, लेकिन यह ओओएम के लिए गिना नहीं जाता है, इसलिए इसके बारे में चिंता करने की आवश्यकता नहीं है।

फिर, चलो हनी कंघी से एसडीके स्टार्ट्स के बारे में बात करते हैं।

  1. बिटमैप वीएम ढेर में संग्रहीत है, ओओएम के लिए मूल स्मृति की गणना नहीं की जाती है।

  2. ओओएम की स्थिति बहुत आसान है: {वीएम ढेर आकार}> = {डिवाइस के लिए वीएम ढेर आकार सीमा}।

  3. तो आपके पास एक ही ढेर आकार सीमा के साथ बिटमैप बनाने के लिए अधिक उपलब्ध स्मृति है, ओओएम को फेंकने की संभावना कम है।

कचरा संग्रह और मेमोरी लीक के बारे में मेरे कुछ अवलोकन यहां दिए गए हैं।

आप इसे ऐप में देख सकते हैं। अगर किसी गतिविधि ने एसिंक टास्क को निष्पादित किया जो गतिविधि को नष्ट करने के बाद भी चल रहा था, तो एसिंक टास्क खत्म होने तक गतिविधि को कचरा नहीं मिलेगा।

ऐसा इसलिए है क्योंकि AsyncTask एक अज्ञात आंतरिक वर्ग का उदाहरण है, इसमें गतिविधि का संदर्भ है।

पृष्ठभूमि थ्रेड में आईओ ऑपरेशन में कार्य अवरुद्ध होने पर AsyncTask.cancel (true) को कॉल करना निष्पादन को रोक नहीं देगा।

कॉलबैक अज्ञात भीतरी कक्षाएं हैं, इसलिए यदि आपकी परियोजना में एक स्थिर उदाहरण उन्हें रखता है और उन्हें जारी नहीं करता है, तो स्मृति लीक हो जाएगी।

यदि आपने दोहराने या देरी किए गए कार्य को निर्धारित किया है, उदाहरण के लिए एक टाइमर, और आप रद्द () और purge () को ऑन पॉज़ () में कॉल नहीं करते हैं, तो स्मृति लीक हो जाएगी।


मैं आईओएस अनुभव से आया हूं और मैं एक छवि को लोड करने और दिखाने के रूप में कुछ बुनियादी के साथ एक मुद्दा खोजने के लिए निराश था। आखिरकार, इस समस्या वाले सभी को उचित आकार वाली छवियां प्रदर्शित करने का प्रयास कर रहा है। वैसे भी, यहां दो बदलाव हैं जो मेरी समस्या को ठीक करते हैं (और मेरे ऐप को बहुत ही उत्तरदायी बनाते हैं)।

1) हर बार जब आप BitmapFactory.decodeXYZ() , तो BitmapFactory.decodeXYZ() को पास करने योग्य सुनिश्चित करने के लिए सुनिश्चित करें (और अधिमानतः inInputShareable भी true सेट करें)।

2) कभी भी Bitmap.createBitmap(width, height, Config.ARGB_8888) । मेरा मतलब कभी नहीं है! मैंने कभी ऐसा नहीं किया है कि कुछ गुजरने के बाद मेमोरी त्रुटि नहीं बढ़ी है। recycle() , System.gc() की कोई मात्रा नहीं, जो भी मदद की। यह हमेशा अपवाद उठाया। वास्तव में काम करने वाला एक अन्य तरीका है कि आपके ड्रॉबल्स में एक डमी छवि (या ऊपर दिए गए चरण 1 का उपयोग करके डीकोड किया गया एक और बिटमैप), जो कुछ भी आप चाहते हैं उसे पुन: प्राप्त करें, फिर परिणामी बिटमैप (जैसे इसे कैनवास पर पास करना) अधिक मज़ा के लिए)। तो, इसके बजाय आपको क्या उपयोग करना चाहिए: Bitmap.createScaledBitmap(srcBitmap, width, height, false) । यदि किसी भी कारण से आपको ब्रूट फोर्स विधि का उपयोग करना चाहिए, तो कम से कम Config.ARGB_4444 पास Config.ARGB_4444

यह आपको दिनों में बचाने के लिए लगभग घंटों की बचत करने की गारंटी देता है। छवि को स्केल करने के बारे में जो भी बात है, इत्यादि वास्तव में काम नहीं करती है (जब तक कि आप गलत आकार या अव्यवस्थित छवि को हल करने पर विचार न करें)।


मैंने फेडरर के कोड में थोड़ा सुधार किया है। यह मूल रूप से वही करता है, लेकिन लूप के दौरान (मेरी राय में) बदसूरत और यह हमेशा दो की शक्ति में परिणाम देता है। मूल समाधान करने के लिए फेडरर के लिए कुडोस, जब तक मैंने उसे नहीं पाया, तब तक अटक गया, और फिर मैं इसे बनाने में सक्षम था :)

 private Bitmap decodeFile(File f){
    Bitmap b = null;

        //Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;

    FileInputStream fis = new FileInputStream(f);
    BitmapFactory.decodeStream(fis, null, o);
    fis.close();

    int scale = 1;
    if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {
        scale = (int)Math.pow(2, (int) Math.ceil(Math.log(IMAGE_MAX_SIZE / 
           (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
    }

    //Decode with inSampleSize
    BitmapFactory.Options o2 = new BitmapFactory.Options();
    o2.inSampleSize = scale;
    fis = new FileInputStream(f);
    b = BitmapFactory.decodeStream(fis, null, o2);
    fis.close();

    return b;
}

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

समाधान : छवियों को "संपत्ति" फ़ोल्डर में ले जाएं और बिटमैप ड्रायबल प्राप्त करने के लिए निम्न फ़ंक्शन का उपयोग करें:

public static Drawable getAssetImage(Context context, String filename) throws IOException {
    AssetManager assets = context.getResources().getAssets();
    InputStream buffer = new BufferedInputStream((assets.open("drawable/" + filename + ".png")));
    Bitmap bitmap = BitmapFactory.decodeStream(buffer);
    return new BitmapDrawable(context.getResources(), bitmap);
}

यह मेरे लिए काम करता है।

Bitmap myBitmap;

BitmapFactory.Options options = new BitmapFactory.Options(); 
options.InPurgeable = true;
options.OutHeight = 50;
options.OutWidth = 50;
options.InSampleSize = 4;

File imgFile = new File(filepath);
myBitmap = BitmapFactory.DecodeFile(imgFile.AbsolutePath, options);

and this is on C# monodroid. you can easily change the path of the image. what important here is the options to be set.


एंड्रॉइड ट्रेनिंग क्लास, " बिटमैप्स को कुशलतापूर्वक प्रदर्शित करना ", अपवाद java.lang.OutOfMemoryError: bitmap size exceeds VM budget को समझने और java.lang.OutOfMemoryError: bitmap size exceeds VM budget निपटने के लिए कुछ अच्छी जानकारी प्रदान करता है java.lang.OutOfMemoryError: bitmap size exceeds VM budget लोड करते समय java.lang.OutOfMemoryError: bitmap size exceeds VM budget

बिटमैप आयाम और प्रकार पढ़ें

BitmapFactory क्लास विभिन्न स्रोतों से Bitmap बनाने के लिए कई डीकोडिंग विधियों ( decodeByteArray() , decodeFile() , decodeResource() , आदि) प्रदान करता है। अपने छवि डेटा स्रोत के आधार पर सबसे उपयुक्त डिकोड विधि चुनें। ये विधियां निर्मित बिटमैप के लिए स्मृति आवंटित करने का प्रयास करती हैं और इसलिए आसानी से OutOfMemory अपवाद का परिणाम हो सकता है। प्रत्येक प्रकार की डिकोड विधि में अतिरिक्त हस्ताक्षर होते हैं जो आपको BitmapFactory.Options क्लास के माध्यम से डिकोडिंग विकल्प निर्दिष्ट करने BitmapFactory.Options । डिकोडिंग मेमोरी आवंटन से बचाता है, बिटमैप ऑब्जेक्ट के लिए null लौट रहा है लेकिन बाहर outWidth , outHeight और outMimeType outHeight करना inJustDecodeBounds प्रॉपर्टी को true सेट करना। यह तकनीक आपको बिटमैप के निर्माण (और स्मृति आवंटन) से पहले छवि डेटा के आयामों और प्रकार को पढ़ने की अनुमति देती है।

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

java.lang.OutOfMemory अपवादों से बचने के लिए, इसे डीकोड करने से पहले बिटमैप के आयामों की जांच करें, जब तक कि आप पूरी तरह से उपलब्ध छवि डेटा प्रदान करने के लिए स्रोत पर भरोसा न करें जो आसानी से उपलब्ध स्मृति के भीतर फिट बैठता है।

मेमोरी में एक स्केल्ड डाउन वर्जन लोड करें

अब जब छवि आयाम ज्ञात हैं, तो इन्हें यह तय करने के लिए उपयोग किया जा सकता है कि पूर्ण छवि को स्मृति में लोड किया जाना चाहिए या यदि उपसमूह संस्करण को इसके बजाय लोड किया जाना चाहिए। विचार करने के लिए यहां कुछ कारक दिए गए हैं:

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

उदाहरण के लिए, 1024x768 पिक्सेल छवि को स्मृति में लोड करने के लायक नहीं है अगर यह अंततः एक ImageView में 128x96 पिक्सेल थंबनेल में प्रदर्शित किया जाएगा।

डीकोडर को छवि को कम करने के लिए, स्मृति में एक छोटा संस्करण लोड करने के लिए, अपने BitmapFactory.Options ऑब्जेक्ट में inSampleSize में true में सेट करें। उदाहरण के लिए, संकल्प 2048x1536 के साथ एक छवि जिसे 4 में inSampleSize के साथ डीकोड किया गया है, लगभग inSampleSize का बिटमैप उत्पन्न करता है। इसे मेमोरी में लोड करना पूरी छवि के लिए 12 एमबी की बजाय 0.75 एमबी का उपयोग करता है ( ARGB_8888 की बिटमैप कॉन्फ़िगरेशन मानते हुए)। नमूना आकार मान की गणना करने के लिए यहां एक विधि है जो लक्ष्य चौड़ाई और ऊंचाई के आधार पर दो की शक्ति है:

public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}

नोट : दो मानों की एक शक्ति की गणना की जाती है क्योंकि inSampleSize दस्तावेज़ों के अनुसार, inSampleSize दो की नजदीकी शक्ति को गोल करके अंतिम मान का उपयोग करता है।

इस विधि का उपयोग करने के लिए, पहले inJustDecodeBounds को true सेट करने के साथ डीकोड करें, विकल्प को पास करें और फिर नए inSampleSize मान का उपयोग करके फिर से डीकोड करें और inJustDecodeBounds को false सेट करें:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
    int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

यह विधि एक ImageView में मनमाने ढंग से बड़े आकार के बिटमैप को लोड करना आसान बनाता है जो 100x100 पिक्सेल थंबनेल प्रदर्शित करता है, जैसा कि निम्न उदाहरण कोड में दिखाया गया है:

mImageView.setImageBitmap(
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

आप आवश्यकतानुसार उचित BitmapFactory.decode* विधि को प्रतिस्थापित करके, अन्य स्रोतों से बिटमैप्स को डीकोड करने के लिए एक समान प्रक्रिया का पालन कर सकते हैं।


unfortunately if None of the Above works, then Add this to your Manifest file. Inside application tag

 <application
         android:largeHeap="true"

Generally android device heap size is only 16MB (varies from device/OS see post Heap Sizes ), if you are loading the images and it crosses the size of 16MB , it will throw out of memory exception, instead of using the Bitmap for , loading images from SD card or from resources or even from network try to using getImageUri , loading bitmap require more memory , or you can set bitmap to null if your work done with that bitmap.


Great answers here, but I wanted a fully usable class to address this problem.. so I did one.

Here is my BitmapHelper class that is OutOfMemoryError proof :-)

import java.io.File;
import java.io.FileInputStream;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;

public class BitmapHelper
{

    //decodes image and scales it to reduce memory consumption
    public static Bitmap decodeFile(File bitmapFile, int requiredWidth, int requiredHeight, boolean quickAndDirty)
    {
        try
        {
            //Decode image size
            BitmapFactory.Options bitmapSizeOptions = new BitmapFactory.Options();
            bitmapSizeOptions.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(new FileInputStream(bitmapFile), null, bitmapSizeOptions);

            // load image using inSampleSize adapted to required image size
            BitmapFactory.Options bitmapDecodeOptions = new BitmapFactory.Options();
            bitmapDecodeOptions.inTempStorage = new byte[16 * 1024];
            bitmapDecodeOptions.inSampleSize = computeInSampleSize(bitmapSizeOptions, requiredWidth, requiredHeight, false);
            bitmapDecodeOptions.inPurgeable = true;
            bitmapDecodeOptions.inDither = !quickAndDirty;
            bitmapDecodeOptions.inPreferredConfig = quickAndDirty ? Bitmap.Config.RGB_565 : Bitmap.Config.ARGB_8888;

            Bitmap decodedBitmap = BitmapFactory.decodeStream(new FileInputStream(bitmapFile), null, bitmapDecodeOptions);

            // scale bitmap to mathc required size (and keep aspect ratio)

            float srcWidth = (float) bitmapDecodeOptions.outWidth;
            float srcHeight = (float) bitmapDecodeOptions.outHeight;

            float dstWidth = (float) requiredWidth;
            float dstHeight = (float) requiredHeight;

            float srcAspectRatio = srcWidth / srcHeight;
            float dstAspectRatio = dstWidth / dstHeight;

            // recycleDecodedBitmap is used to know if we must recycle intermediary 'decodedBitmap'
            // (DO NOT recycle it right away: wait for end of bitmap manipulation process to avoid
            // java.lang.RuntimeException: Canvas: trying to use a recycled bitmap [email protected]
            // I do not excatly understand why, but this way it's OK

            boolean recycleDecodedBitmap = false;

            Bitmap scaledBitmap = decodedBitmap;
            if (srcAspectRatio < dstAspectRatio)
            {
                scaledBitmap = getScaledBitmap(decodedBitmap, (int) dstWidth, (int) (srcHeight * (dstWidth / srcWidth)));
                // will recycle recycleDecodedBitmap
                recycleDecodedBitmap = true;
            }
            else if (srcAspectRatio > dstAspectRatio)
            {
                scaledBitmap = getScaledBitmap(decodedBitmap, (int) (srcWidth * (dstHeight / srcHeight)), (int) dstHeight);
                recycleDecodedBitmap = true;
            }

            // crop image to match required image size

            int scaledBitmapWidth = scaledBitmap.getWidth();
            int scaledBitmapHeight = scaledBitmap.getHeight();

            Bitmap croppedBitmap = scaledBitmap;

            if (scaledBitmapWidth > requiredWidth)
            {
                int xOffset = (scaledBitmapWidth - requiredWidth) / 2;
                croppedBitmap = Bitmap.createBitmap(scaledBitmap, xOffset, 0, requiredWidth, requiredHeight);
                scaledBitmap.recycle();
            }
            else if (scaledBitmapHeight > requiredHeight)
            {
                int yOffset = (scaledBitmapHeight - requiredHeight) / 2;
                croppedBitmap = Bitmap.createBitmap(scaledBitmap, 0, yOffset, requiredWidth, requiredHeight);
                scaledBitmap.recycle();
            }

            if (recycleDecodedBitmap)
            {
                decodedBitmap.recycle();
            }
            decodedBitmap = null;

            scaledBitmap = null;
            return croppedBitmap;
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
        return null;
    }

    /**
     * compute powerOf2 or exact scale to be used as {@link BitmapFactory.Options#inSampleSize} value (for subSampling)
     * 
     * @param requiredWidth
     * @param requiredHeight
     * @param powerOf2
     *            weither we want a power of 2 sclae or not
     * @return
     */
    public static int computeInSampleSize(BitmapFactory.Options options, int dstWidth, int dstHeight, boolean powerOf2)
    {
        int inSampleSize = 1;

        // Raw height and width of image
        final int srcHeight = options.outHeight;
        final int srcWidth = options.outWidth;

        if (powerOf2)
        {
            //Find the correct scale value. It should be the power of 2.

            int tmpWidth = srcWidth, tmpHeight = srcHeight;
            while (true)
            {
                if (tmpWidth / 2 < dstWidth || tmpHeight / 2 < dstHeight)
                    break;
                tmpWidth /= 2;
                tmpHeight /= 2;
                inSampleSize *= 2;
            }
        }
        else
        {
            // Calculate ratios of height and width to requested height and width
            final int heightRatio = Math.round((float) srcHeight / (float) dstHeight);
            final int widthRatio = Math.round((float) srcWidth / (float) dstWidth);

            // Choose the smallest ratio as inSampleSize value, this will guarantee
            // a final image with both dimensions larger than or equal to the
            // requested height and width.
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }

        return inSampleSize;
    }

    public static Bitmap drawableToBitmap(Drawable drawable)
    {
        if (drawable instanceof BitmapDrawable)
        {
            return ((BitmapDrawable) drawable).getBitmap();
        }

        Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);

        return bitmap;
    }

    public static Bitmap getScaledBitmap(Bitmap bitmap, int newWidth, int newHeight)
    {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;

        // CREATE A MATRIX FOR THE MANIPULATION
        Matrix matrix = new Matrix();
        // RESIZE THE BIT MAP
        matrix.postScale(scaleWidth, scaleHeight);

        // RECREATE THE NEW BITMAP
        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
        return resizedBitmap;
    }

}

I have a much more effective solution which does not need scaling of any sort. Simply decode your bitmap only once and then cache it in a map against its name. Then simply retrieve the bitmap against the name and set it in the ImageView. There is nothing more that needs to be done.

This will work because the actual binary data of the decoded bitmap is not stored within the dalvik VM heap. It is stored externally. So every time you decode a bitmap, it allocates memory outside of VM heap which is never reclaimed by GC

To help you better appreciate this, imagine you have kept ur image in the drawable folder. You just get the image by doing a getResources().getDrwable(R.drawable.). This will NOT decode your image everytime but re-use an already decoded instance everytime you call it. So in essence it is cached.

Now since your image is in a file somewhere (or may even be coming from an external server), it is YOUR responsibility to cache the decoded bitmap instance to be reused any where it is needed.

उम्मीद है की यह मदद करेगा।


I have resolved the same issue in the following manner.

Bitmap b = null;
Drawable d;
ImageView i = new ImageView(mContext);
try {
    b = Bitmap.createBitmap(320,424,Bitmap.Config.RGB_565);
    b.eraseColor(0xFFFFFFFF);
    Rect r = new Rect(0, 0,320 , 424);
    Canvas c = new Canvas(b);
    Paint p = new Paint();
    p.setColor(0xFFC0C0C0);
    c.drawRect(r, p);
    d = mContext.getResources().getDrawable(mImageIds[position]);
    d.setBounds(r);
    d.draw(c);

    /*   
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inTempStorage = new byte[128*1024];
        b = BitmapFactory.decodeStream(mContext.getResources().openRawResource(mImageIds[position]), null, o2);
        o2.inSampleSize=16;
        o2.inPurgeable = true;
    */
} catch (Exception e) {

}
i.setImageBitmap(b);

I've spent the entire day testing these solutions and the only thing that worked for me is the above approaches for getting the image and manually calling the GC, which I know is not supposed to be necessary, but it is the only thing that worked when I put my app under heavy load testing switching between activities. My app has a list of thumbnail images in a listview in (lets say activity A) and when you click on one of those images it takes you to another activity (lets say activity B) that shows a main image for that item. When I would switch back and forth between the two activities, I would eventually get the OOM error and the app would force close.

When I would get half way down the listview it would crash.

Now when I implement the following in activity B, I can go through the entire listview with no issue and keep going and going and going...and its plenty fast.

@Override
public void onDestroy()
{   
    Cleanup();
    super.onDestroy();
}

private void Cleanup()
{    
    bitmap.recycle();
    System.gc();
    Runtime.getRuntime().gc();  
}

In one of my application i need to take picture either from Camera/Gallery . If user click image from Camera(may be 2MP, 5MP or 8MP), image size varies from kB s to MB s. If image size is less(or up to 1-2MB) above code working fine but if i have image of size above 4MB or 5MB then OOM comes in frame :(

then i have worked to solve this issue & finally i've made the below improvement to Fedor's(All Credit to Fedor for making such a nice solution) code :)

private Bitmap decodeFile(String fPath) {
    // Decode image size
    BitmapFactory.Options opts = new BitmapFactory.Options();
    /*
     * If set to true, the decoder will return null (no bitmap), but the
     * out... fields will still be set, allowing the caller to query the
     * bitmap without having to allocate the memory for its pixels.
     */
    opts.inJustDecodeBounds = true;
    opts.inDither = false; // Disable Dithering mode
    opts.inPurgeable = true; // Tell to gc that whether it needs free
                                // memory, the Bitmap can be cleared
    opts.inInputShareable = true; // Which kind of reference will be used to
                                    // recover the Bitmap data after being
                                    // clear, when it will be used in the
                                    // future

    BitmapFactory.decodeFile(fPath, opts);

    // The new size we want to scale to
    final int REQUIRED_SIZE = 70;

    // Find the correct scale value. 
    int scale = 1;

    if (opts.outHeight > REQUIRED_SIZE || opts.outWidth > REQUIRED_SIZE) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) opts.outHeight
                / (float) REQUIRED_SIZE);
        final int widthRatio = Math.round((float) opts.outWidth
                / (float) REQUIRED_SIZE);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        scale = heightRatio < widthRatio ? heightRatio : widthRatio;//
    }

    // Decode bitmap with inSampleSize set
    opts.inJustDecodeBounds = false;

    opts.inSampleSize = scale;

    Bitmap bm = BitmapFactory.decodeFile(fPath, opts).copy(
            Bitmap.Config.RGB_565, false);

    return bm;

}

I hope this will help the buddies facing the same problem!

for more please refer this


My 2 cents: i solved my OOM errors with bitmaps by:

a) scaling my images by a factor of 2

b) using Picasso library in my custom Adapter for a ListView, with a one-call in getView like this: Picasso.with(context).load(R.id.myImage).into(R.id.myImageView);


None of the answers above worked for me, but I did come up with a horribly ugly workaround that solved the problem. I added a very small, 1x1 pixel image to my project as a resource, and loaded it into my ImageView before calling into garbage collection. I think it might be that the ImageView was not releasing the Bitmap, so GC never picked it up. It's ugly, but it seems to be working for now.

if (bitmap != null)
{
  bitmap.recycle();
  bitmap = null;
}
if (imageView != null)
{
  imageView.setImageResource(R.drawable.tiny); // This is my 1x1 png.
}
System.gc();

imageView.setImageBitmap(...); // Do whatever you need to do to load the image you want.

There are two issues here....

  • Bitmap memory isn't in the VM heap but rather in the native heap - see BitmapFactory OOM driving me nuts
  • Garbage collection for the native heap is lazier than the VM heap - so you need to be quite aggressive about doing bitmap.recycle and bitmap =null every time you go through an Activity's onPause or onDestroy

This code will help to load large bitmap from drawable

public class BitmapUtilsTask extends AsyncTask<Object, Void, Bitmap> {

Context context;

public BitmapUtilsTask(Context context) {
    this.context = context;
}

/**
 * Loads a bitmap from the specified url.
 * 
 * @param url The location of the bitmap asset
 * @return The bitmap, or null if it could not be loaded
 * @throws IOException
 * @throws MalformedURLException
 */
public Bitmap getBitmap() throws MalformedURLException, IOException {       

    // Get the source image's dimensions
    int desiredWidth = 1000;
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;

    BitmapFactory.decodeResource(context.getResources(), R.drawable.green_background , options);

    int srcWidth = options.outWidth;
    int srcHeight = options.outHeight;

    // Only scale if the source is big enough. This code is just trying
    // to fit a image into a certain width.
    if (desiredWidth > srcWidth)
        desiredWidth = srcWidth;

    // Calculate the correct inSampleSize/scale value. This helps reduce
    // memory use. It should be a power of 2
    int inSampleSize = 1;
    while (srcWidth / 2 > desiredWidth) {
        srcWidth /= 2;
        srcHeight /= 2;
        inSampleSize *= 2;
    }
    // Decode with inSampleSize
    options.inJustDecodeBounds = false;
    options.inDither = false;
    options.inSampleSize = inSampleSize;
    options.inScaled = false;
    options.inPreferredConfig = Bitmap.Config.ARGB_8888;
    options.inPurgeable = true;
    Bitmap sampledSrcBitmap;

    sampledSrcBitmap =  BitmapFactory.decodeResource(context.getResources(), R.drawable.green_background , options);

    return sampledSrcBitmap;
}

/**
 * The system calls this to perform work in a worker thread and delivers
 * it the parameters given to AsyncTask.execute()
 */
@Override
protected Bitmap doInBackground(Object... item) {

    try 
    { 
      return getBitmap();
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
 }

}


This seems like the appropriate place to share my utility class for loading and processing images with the community, you are welcome to use it and modify it freely.

package com.emil;

import java.io.IOException;
import java.io.InputStream;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

/**
 * A class to load and process images of various sizes from input streams and file paths.
 * 
 * @author Emil http://.com/users/220710/emil
 *
 */
public class ImageProcessing {

    public static Bitmap getBitmap(InputStream stream, int sampleSize, Bitmap.Config bitmapConfig) throws IOException{
        BitmapFactory.Options options=ImageProcessing.getOptionsForSampling(sampleSize, bitmapConfig);
        Bitmap bm = BitmapFactory.decodeStream(stream,null,options);
        if(ImageProcessing.checkDecode(options)){
            return bm;
        }else{
            throw new IOException("Image decoding failed, using stream.");
        }
    }

    public static Bitmap getBitmap(String imgPath, int sampleSize, Bitmap.Config bitmapConfig) throws IOException{
        BitmapFactory.Options options=ImageProcessing.getOptionsForSampling(sampleSize, bitmapConfig);
        Bitmap bm = BitmapFactory.decodeFile(imgPath,options);
        if(ImageProcessing.checkDecode(options)){
            return bm;
        }else{
            throw new IOException("Image decoding failed, using file path.");
        }
    }

    public static Dimensions getDimensions(InputStream stream) throws IOException{
        BitmapFactory.Options options=ImageProcessing.getOptionsForDimensions();
        BitmapFactory.decodeStream(stream,null,options);
        if(ImageProcessing.checkDecode(options)){
            return new ImageProcessing.Dimensions(options.outWidth,options.outHeight);
        }else{
            throw new IOException("Image decoding failed, using stream.");
        }
    }

    public static Dimensions getDimensions(String imgPath) throws IOException{
        BitmapFactory.Options options=ImageProcessing.getOptionsForDimensions();
        BitmapFactory.decodeFile(imgPath,options);
        if(ImageProcessing.checkDecode(options)){
            return new ImageProcessing.Dimensions(options.outWidth,options.outHeight);
        }else{
            throw new IOException("Image decoding failed, using file path.");
        }
    }

    private static boolean checkDecode(BitmapFactory.Options options){
        // Did decode work?
        if( options.outWidth<0 || options.outHeight<0 ){
            return false;
        }else{
            return true;
        }
    }

    /**
     * Creates a Bitmap that is of the minimum dimensions necessary
     * @param bm
     * @param min
     * @return
     */
    public static Bitmap createMinimalBitmap(Bitmap bm, ImageProcessing.Minimize min){
        int newWidth, newHeight;
        switch(min.type){
        case WIDTH:
            if(bm.getWidth()>min.minWidth){
                newWidth=min.minWidth;
                newHeight=ImageProcessing.getScaledHeight(newWidth, bm);
            }else{
                // No resize
                newWidth=bm.getWidth();
                newHeight=bm.getHeight();
            }
            break;
        case HEIGHT:
            if(bm.getHeight()>min.minHeight){
                newHeight=min.minHeight;
                newWidth=ImageProcessing.getScaledWidth(newHeight, bm);
            }else{
                // No resize
                newWidth=bm.getWidth();
                newHeight=bm.getHeight();
            }
            break;
        case BOTH: // minimize to the maximum dimension
        case MAX:
            if(bm.getHeight()>bm.getWidth()){
                // Height needs to minimized
                min.minDim=min.minDim!=null ? min.minDim : min.minHeight;
                if(bm.getHeight()>min.minDim){
                    newHeight=min.minDim;
                    newWidth=ImageProcessing.getScaledWidth(newHeight, bm);
                }else{
                    // No resize
                    newWidth=bm.getWidth();
                    newHeight=bm.getHeight();
                }
            }else{
                // Width needs to be minimized
                min.minDim=min.minDim!=null ? min.minDim : min.minWidth;
                if(bm.getWidth()>min.minDim){
                    newWidth=min.minDim;
                    newHeight=ImageProcessing.getScaledHeight(newWidth, bm);
                }else{
                    // No resize
                    newWidth=bm.getWidth();
                    newHeight=bm.getHeight();
                }
            }
            break;
        default:
            // No resize
            newWidth=bm.getWidth();
            newHeight=bm.getHeight();
        }
        return Bitmap.createScaledBitmap(bm, newWidth, newHeight, true);
    }

    public static int getScaledWidth(int height, Bitmap bm){
        return (int)(((double)bm.getWidth()/bm.getHeight())*height);
    }

    public static int getScaledHeight(int width, Bitmap bm){
        return (int)(((double)bm.getHeight()/bm.getWidth())*width);
    }

    /**
     * Get the proper sample size to meet minimization restraints
     * @param dim
     * @param min
     * @param multipleOf2 for fastest processing it is recommended that the sample size be a multiple of 2
     * @return
     */
    public static int getSampleSize(ImageProcessing.Dimensions dim, ImageProcessing.Minimize min, boolean multipleOf2){
        switch(min.type){
        case WIDTH:
            return ImageProcessing.getMaxSampleSize(dim.width, min.minWidth, multipleOf2);
        case HEIGHT:
            return ImageProcessing.getMaxSampleSize(dim.height, min.minHeight, multipleOf2);
        case BOTH:
            int widthMaxSampleSize=ImageProcessing.getMaxSampleSize(dim.width, min.minWidth, multipleOf2);
            int heightMaxSampleSize=ImageProcessing.getMaxSampleSize(dim.height, min.minHeight, multipleOf2);
            // Return the smaller of the two
            if(widthMaxSampleSize<heightMaxSampleSize){
                return widthMaxSampleSize;
            }else{
                return heightMaxSampleSize;
            }
        case MAX:
            // Find the larger dimension and go bases on that
            if(dim.width>dim.height){
                return ImageProcessing.getMaxSampleSize(dim.width, min.minDim, multipleOf2);
            }else{
                return ImageProcessing.getMaxSampleSize(dim.height, min.minDim, multipleOf2);
            }
        }
        return 1;
    }

    public static int getMaxSampleSize(int dim, int min, boolean multipleOf2){
        int add=multipleOf2 ? 2 : 1;
        int size=0;
        while(min<(dim/(size+add))){
            size+=add;
        }
        size = size==0 ? 1 : size;
        return size;        
    }

    public static class Dimensions {
        int width;
        int height;

        public Dimensions(int width, int height) {
            super();
            this.width = width;
            this.height = height;
        }

        @Override
        public String toString() {
            return width+" x "+height;
        }
    }

    public static class Minimize {
        public enum Type {
            WIDTH,HEIGHT,BOTH,MAX
        }
        Integer minWidth;
        Integer minHeight;
        Integer minDim;
        Type type;

        public Minimize(int min, Type type) {
            super();
            this.type = type;
            switch(type){
            case WIDTH:
                this.minWidth=min;
                break;
            case HEIGHT:
                this.minHeight=min;
                break;
            case BOTH:
                this.minWidth=min;
                this.minHeight=min;
                break;
            case MAX:
                this.minDim=min;
                break;
            }
        }

        public Minimize(int minWidth, int minHeight) {
            super();
            this.type=Type.BOTH;
            this.minWidth = minWidth;
            this.minHeight = minHeight;
        }

    }

    /**
     * Estimates size of Bitmap in bytes depending on dimensions and Bitmap.Config
     * @param width
     * @param height
     * @param config
     * @return
     */
    public static long estimateBitmapBytes(int width, int height, Bitmap.Config config){
        long pixels=width*height;
        switch(config){
        case ALPHA_8: // 1 byte per pixel
            return pixels;
        case ARGB_4444: // 2 bytes per pixel, but depreciated
            return pixels*2;
        case ARGB_8888: // 4 bytes per pixel
            return pixels*4;
        case RGB_565: // 2 bytes per pixel
            return pixels*2;
        default:
            return pixels;
        }
    }

    private static BitmapFactory.Options getOptionsForDimensions(){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds=true;
        return options;
    }

    private static BitmapFactory.Options getOptionsForSampling(int sampleSize, Bitmap.Config bitmapConfig){
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = false;
        options.inDither = false;
        options.inSampleSize = sampleSize;
        options.inScaled = false;
        options.inPreferredConfig = bitmapConfig;
        return options;
    }
}

Use this bitmap.recycle(); This helps without any image quality issue.





android-bitmap