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




image bitmap (24)

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

सूची दृश्य पर छवि पूर्वावलोकन कर्सर और 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

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

 <application
         android:largeHeap="true"

I just ran into this issue a couple minutes ago. I solved it by doing a better job at managing my listview adapter. I thought it was an issue with the hundreds of 50x50px images I was using, turns out I was trying to inflate my custom view each time the row was being shown. Simply by testing to see if the row had been inflated I eliminated this error, and I am using hundreds of bitmaps. This is actually for a Spinner, but the base adapter works all the same for a ListView. This simple fix also greatly improved the performance of the adapter.

@Override
public View getView(final int position, View convertView, final ViewGroup parent) {

    if(convertView == null){
        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.spinner_row, null);
    }
...

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

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

मेरे पास यह वही समस्या थी और BitmapFactory.decodeStream या decodeFile कार्यों से बचकर इसे हल किया और इसके बजाय BitmapFactory.decodeFileDescriptor उपयोग किया

decodeFileDescriptor लगता है जैसे यह decodeStream / decodeFile की तुलना में विभिन्न मूल विधियों को कॉल करता है।

वैसे भी, यह क्या काम किया गया था (ध्यान दें कि मैंने कुछ विकल्पों को जोड़ा है जैसा कि ऊपर था, लेकिन इससे कोई फर्क नहीं पड़ता। यह महत्वपूर्ण है कि डीकोडस्ट्रीम या डीकोडफाइल के बजाय बिटमैप फैक्टरी.decodeFileDescriptor को कॉल करें):

private void showImage(String path)   {
    Log.i("showImage","loading:"+path);
    BitmapFactory.Options bfOptions=new BitmapFactory.Options();
    bfOptions.inDither=false;                     //Disable Dithering mode
    bfOptions.inPurgeable=true;                   //Tell to gc that whether it needs free memory, the Bitmap can be cleared
    bfOptions.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
    bfOptions.inTempStorage=new byte[32 * 1024]; 


    File file=new File(path);
    FileInputStream fs=null;
    try {
        fs = new FileInputStream(file);
    } catch (FileNotFoundException e) {
        //TODO do something intelligent
        e.printStackTrace();
    }

    try {
        if(fs!=null) bm=BitmapFactory.decodeFileDescriptor(fs.getFD(), null, bfOptions);
    } catch (IOException e) {
        //TODO do something intelligent
        e.printStackTrace();
    } finally{ 
        if(fs!=null) {
            try {
                fs.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    //bm=BitmapFactory.decodeFile(path, bfOptions); This one causes error: java.lang.OutOfMemoryError: bitmap size exceeds VM budget

    im.setImageBitmap(bm);
    //bm.recycle();
    bm=null;



}

मुझे लगता है कि decodeStream / decodeFile में उपयोग किए गए देशी फ़ंक्शन में कोई समस्या है। मैंने पुष्टि की है कि decodeFileDescriptor का उपयोग करते समय एक अलग देशी विधि कहा जाता है। मैंने जो भी पढ़ा है वह यह है कि "छवियों (बिटमैप्स) को मानक जावा तरीके से आवंटित नहीं किया जाता है लेकिन देशी कॉल के माध्यम से आवंटन वर्चुअल ढेर के बाहर किया जाता है, लेकिन इसके खिलाफ गिना जाता है! "


All the solutions here require setting a IMAGE_MAX_SIZE. This limits devices with more powerful hardware and if the image size is too low it looks ugly on the HD screen.

I came out with a solution that works with my Samsung Galaxy S3 and several other devices including less powerful ones, with better image quality when a more powerful device is used.

The gist of it is to calculate the maximum memory allocated for the app on a particular device, then set the scale to be lowest possible without exceeding this memory. यहां कोड है:

public static Bitmap decodeFile(File f)
{
    Bitmap b = null;
    try
    {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;

        FileInputStream fis = new FileInputStream(f);
        try
        {
            BitmapFactory.decodeStream(fis, null, o);
        }
        finally
        {
            fis.close();
        }

        // In Samsung Galaxy S3, typically max memory is 64mb
        // Camera max resolution is 3264 x 2448, times 4 to get Bitmap memory of 30.5mb for one bitmap
        // If we use scale of 2, resolution will be halved, 1632 x 1224 and x 4 to get Bitmap memory of 7.62mb
        // We try use 25% memory which equals to 16mb maximum for one bitmap
        long maxMemory = Runtime.getRuntime().maxMemory();
        int maxMemoryForImage = (int) (maxMemory / 100 * 25);

        // Refer to
        // http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
        // A full screen GridView filled with images on a device with
        // 800x480 resolution would use around 1.5MB (800*480*4 bytes)
        // When bitmap option's inSampleSize doubled, pixel height and
        // weight both reduce in half
        int scale = 1;
        while ((o.outWidth / scale) * (o.outHeight / scale) * 4 > maxMemoryForImage)
        scale *= 2;

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        fis = new FileInputStream(f);
        try
        {
            b = BitmapFactory.decodeStream(fis, null, o2);
        }
        finally
        {
            fis.close();
        }
    }
    catch (IOException e)
    {
    }
    return b;
}

I set the maximum memory used by this bitmap to be 25% of maximum allocated memory, you may need to adjust this to your needs and make sure this bitmap is cleaned up and don't stay in memory when you've finished using it. Typically I use this code to perform image rotation (source and destination bitmap) so my app needs to load 2 bitmaps in memory at the same time, and 25% gives me a good buffer without running out of memory when performing image rotation.

Hope this helps someone out there..


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

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

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

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.

I did the following to take the image and resize it on the fly. उम्मीद है की यह मदद करेगा

Bitmap bm;
bm = Bitmap.createScaledBitmap(BitmapFactory.decodeFile(filepath), 100, 100, true);
mPicture = new ImageView(context);
mPicture.setImageBitmap(bm);    

यह मेरे लिए काम किया!

public Bitmap readAssetsBitmap(String filename) throws IOException {
    try {
        BitmapFactory.Options options = new BitmapFactory.Options(); 
        options.inPurgeable = true;
        Bitmap bitmap = BitmapFactory.decodeStream(assets.open(filename), null, options);
        if(bitmap == null) {
            throw new IOException("File cannot be opened: It's value is null");
        } else {
            return bitmap;
        }
    } catch (IOException e) {
        throw new IOException("File cannot be opened: " + e.getMessage());
    }
}

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


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


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

}

It seems that this is a very long running problem, with a lot of differing explanations. I took the advice of the two most common presented answers here, but neither one of these solved my problems of the VM claiming it couldn't afford the bytes to perform the decoding part of the process. After some digging I learned that the real problem here is the decoding process taking away from the NATIVE heap.

See here: BitmapFactory OOM driving me nuts

That lead me to another discussion thread where I found a couple more solutions to this problem. One is to call System.gc(); manually after your image is displayed. But that actually makes your app use MORE memory, in an effort to reduce the native heap. The better solution as of the release of 2.0 (Donut) is to use the BitmapFactory option "inPurgeable". So I simply added o2.inPurgeable=true; just after o2.inSampleSize=scale;

More on that topic here: Is the limit of memory heap only 6M?

Now, having said all of this, I am a complete dunce with Java and Android too. So if you think this is a terrible way to solve this problem, you are probably right. ;-) But this has worked wonders for me, and I have found it impossible to run the VM out of heap cache now. The only drawback I can find is that you are trashing your cached drawn image. Which means if you go RIGHT back to that image, you are redrawing it each and every time. In the case of how my application works, that is not really a problem. आपकी माइलेज भिन्न हो सकती है।


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

मैंने हाल ही में ओओएम अपवादों और कैशिंग के बारे में बहुत सारे प्रश्न देखे हैं। डेवलपर गाइड पर इस पर एक बहुत अच्छा लेख है, लेकिन कुछ इसे उपयुक्त तरीके से लागू करने में विफल रहते हैं।

इस वजह से मैंने एक उदाहरण एप्लिकेशन लिखा जो एंड्रॉइड पर्यावरण में कैशिंग प्रदर्शित करता है। इस कार्यान्वयन को अभी तक ओओएम नहीं मिला है।

स्रोत कोड के लिंक के लिए इस उत्तर के अंत को देखें।

आवश्यकताएँ:

  • एंड्रॉइड एपीआई 2.1 या उच्चतर (मैं बस एपीआई 1.6 में किसी एप्लिकेशन के लिए उपलब्ध मेमोरी प्राप्त करने का प्रबंधन नहीं कर सका - यह कोड का एकमात्र टुकड़ा है जो एपीआई 1.6 में काम नहीं करता है)
  • एंड्रॉइड समर्थन पैकेज

विशेषताएं:

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

इसमें शामिल नहीं है:

  • डिस्क कैशिंग इसे किसी भी तरह कार्यान्वित करना आसान होना चाहिए - बस डिस्क से बिटमैप्स को पकड़ने वाले एक अलग कार्य को इंगित करें

नमूना कोड:

डाउनलोड की जा रही छवियां फ़्लिकर से छवियां (75x75) हैं। हालांकि, जो भी छवि यूआरएल आप संसाधित करना चाहते हैं उसे रखें, और यदि यह अधिकतम से अधिक हो तो एप्लिकेशन इसे घटाएगा। इस एप्लिकेशन में यूआरएल बस एक String सरणी में हैं।

LruCache पास बिटमैप्स से निपटने का एक अच्छा तरीका है। हालांकि, इस एप्लिकेशन में मैंने एक और कैश क्लास के अंदर एक LruCache का एक उदाहरण दिया जिसे मैंने एप्लिकेशन को और अधिक व्यवहार्य बनाने के लिए बनाया था।

कैश.जावा की महत्वपूर्ण सामग्री ( loadBitmap() विधि सबसे महत्वपूर्ण है):

public Cache(int size, int maxWidth, int maxHeight) {
    // Into the constructor you add the maximum pixels
    // that you want to allow in order to not scale images.
    mMaxWidth = maxWidth;
    mMaxHeight = maxHeight;

    mBitmapCache = new LruCache<String, Bitmap>(size) {
        protected int sizeOf(String key, Bitmap b) {
            // Assuming that one pixel contains four bytes.
            return b.getHeight() * b.getWidth() * 4;
        }
    };

    mCurrentTasks = new ArrayList<String>();    
}

/**
 * Gets a bitmap from cache. 
 * If it is not in cache, this method will:
 * 
 * 1: check if the bitmap url is currently being processed in the
 * BitmapLoaderTask and cancel if it is already in a task (a control to see
 * if it's inside the currentTasks list).
 * 
 * 2: check if an internet connection is available and continue if so.
 * 
 * 3: download the bitmap, scale the bitmap if necessary and put it into
 * the memory cache.
 * 
 * 4: Remove the bitmap url from the currentTasks list.
 * 
 * 5: Notify the ListAdapter.
 * 
 * @param mainActivity - Reference to activity object, in order to
 * call notifyDataSetChanged() on the ListAdapter.
 * @param imageKey - The bitmap url (will be the key).
 * @param imageView - The ImageView that should get an
 * available bitmap or a placeholder image.
 * @param isScrolling - If set to true, we skip executing more tasks since
 * the user probably has flinged away the view.
 */
public void loadBitmap(MainActivity mainActivity, 
        String imageKey, ImageView imageView,
        boolean isScrolling) {
    final Bitmap bitmap = getBitmapFromCache(imageKey); 

    if (bitmap != null) {
        imageView.setImageBitmap(bitmap);
    } else {
        imageView.setImageResource(R.drawable.ic_launcher);
        if (!isScrolling && !mCurrentTasks.contains(imageKey) && 
                mainActivity.internetIsAvailable()) {
            BitmapLoaderTask task = new BitmapLoaderTask(imageKey,
                    mainActivity.getAdapter());
            task.execute();
        }
    } 
}

जब तक आप डिस्क कैशिंग लागू नहीं करना चाहते हैं तब तक आपको Cache.java फ़ाइल में कुछ भी संपादित करने की आवश्यकता नहीं है।

MainActivity.java की महत्वपूर्ण सामग्री:

public void onScrollStateChanged(AbsListView view, int scrollState) {
    if (view.getId() == android.R.id.list) {
        // Set scrolling to true only if the user has flinged the       
        // ListView away, hence we skip downloading a series
        // of unnecessary bitmaps that the user probably
        // just want to skip anyways. If we scroll slowly it
        // will still download bitmaps - that means
        // that the application won't wait for the user
        // to lift its finger off the screen in order to
        // download.
        if (scrollState == SCROLL_STATE_FLING) {
            mIsScrolling = true;
        } else {
            mIsScrolling = false;
            mListAdapter.notifyDataSetChanged();
        }
    } 
}

// Inside ListAdapter...
@Override
public View getView(final int position, View convertView, ViewGroup parent) {           
    View row = convertView;
    final ViewHolder holder;

    if (row == null) {
        LayoutInflater inflater = getLayoutInflater();
        row = inflater.inflate(R.layout.main_listview_row, parent, false);  
        holder = new ViewHolder(row);
        row.setTag(holder);
    } else {
        holder = (ViewHolder) row.getTag();
    }   

    final Row rowObject = getItem(position);

    // Look at the loadBitmap() method description...
    holder.mTextView.setText(rowObject.mText);      
    mCache.loadBitmap(MainActivity.this,
            rowObject.mBitmapUrl, holder.mImageView,
            mIsScrolling);  

    return row;
}

getView() gets called very often. It's normally not a good idea to download images there if we haven't implemented a check that ensure us that we won't start an infinite amount of threads per row. Cache.java checks whether the rowObject.mBitmapUrl already is in a task and if it is, it won't start another. Therefore, we are most likely not exceeding the work queue restriction from the AsyncTask pool.

डाउनलोड:

You can download the source code from https://www.dropbox.com/s/pvr9zyl811tfeem/ListViewImageCache.zip .

Last words:

I have tested this for a few weeks now, I haven't gotten a single OOM exception yet. I have tested this on the emulator, on my Nexus One and on my Nexus S. I have tested image urls that contain images that were in HD quality. The only bottleneck is that it takes more time to download.

There is only one possible scenario where I can imagine that the OOM will appear, and that is if we download many, really big images, and before they get scaled and put into cache, will simultaneously take up more memory and cause an OOM. But that isn't even an ideal situation anyway and it most likely won't be possible to solve in a more feasible way.

Report errors in the comments! :-)


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

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.


एंड्रॉइड ट्रेनिंग क्लास, " बिटमैप्स को कुशलतापूर्वक प्रदर्शित करना ", अपवाद 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* विधि को प्रतिस्थापित करके, अन्य स्रोतों से बिटमैप्स को डीकोड करने के लिए एक समान प्रक्रिया का पालन कर सकते हैं।


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

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.


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

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

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

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

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


This issue only happens in Android emulators. I also faced this issue in an emulator but when I checked in a device then it worked fine.

So please check in a device. It may be run in device.


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

}





android-bitmap