Loading large images without OutOfMemoryError

为君一笑 提交于 2019-11-29 01:25:53

Take a look at:

http://developer.android.com/reference/android/graphics/BitmapFactory.html

decodeStream (InputStream is, Rect outPadding, BitmapFactory.Options opts)

or

decodeFile (String pathName, BitmapFactory.Options opts)

this way you can load your whole bitmap and show it on screen.

You need to set the correct options.

http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html

inSampleSize

I tried it with your code:

 BitmapFactory.Options options = new BitmapFactory.Options();

 options.inSampleSize = 4;

 Bitmap myBitmap = BitmapFactory.decodeFile(mUri.getPath(),options);
 Drawable d = new BitmapDrawable(Resources.getSystem(),myBitmap);
 updateDrawable(d);

works for me.

In my opinion, the best option is to split the image into smaller pieces. This will prevent the application to give an OutOfMemoryException. Here is my example code

First get the image from the SD Card an put it into an Bitmap

Bitmap b = null;
        try {
            File sd = new File(Environment.getExternalStorageDirectory() + link_to_image.jpg);
            FileInputStream fis;

            fis = new FileInputStream(sd);

            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inPurgeable = true;
            options.inScaled = false;

            b = BitmapFactory.decodeStream(fis, null, options);
            fis.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

Split the bitmap (b) into smaller pieces. In this case SPLIT_HEIGHT is 400.

double rest = (image_height + SPLIT_HEIGHT);
        int i = 0;
        Bitmap[] imgs = new Bitmap[50];

        do {
            rest -= SPLIT_HEIGHT;
            if (rest < 0) {
                // Do nothing
            } else if (rest < SPLIT_HEIGHT) {
                imgs[i] = Bitmap.createBitmap(b, 0, (i * SPLIT_HEIGHT), image_width, (int) rest);
            } else {
                imgs[i] = Bitmap.createBitmap(b, 0, i * SPLIT_HEIGHT, image_width, SPLIT_HEIGHT);
            }

            i++;

        } while (rest > SPLIT_HEIGHT);

Now you have a collection of smaller images. If you want to do it perfecly, you can recycle this bitmap:

// Not needed anymore, free up some memory
        if (b != null)
            b.recycle();

From this point you can put the smaller images onto the canvas. In my next code I put the images into an ScrollView. The code for putting the images on a Canvas is I think not very different.

// Add images to scrollview
        for (int j = 0; j < imgs.length; j++) {
            Bitmap tmp = imgs[j];
            if (tmp != null) {
                // Add to scrollview
                ImageView iv = new ImageView(activity);

                String id = j + "" + articlenumber;
                iv.setId(Integer.parseInt(id));
                iv.setTag(i);

                iv.setImageBitmap(tmp);

                RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(globalwidth, tmp.getHeight());
                lp.addRule(RelativeLayout.BELOW, previousLongPageImageId);
                lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);

                container.addView(iv, lp);
                previousLongPageImageId = iv.getId();
            }
        }

I hope this will help you.

NOTE: The maximum resolution for images is 2048*2048 (OpenGL restrictions or something), so you will always have to split images into smaller pieces.

I am not sure whether it is the correct of way of doing this but still this can solve your problem.

Try opening your image in a webview. This will provide you in-built zoom-in/out and panning feature and you dont have to worry about opening any input stream or anything else.

To open an image in webview from assets:

    WebView  wv = (WebView) findViewById(R.id.webView1);  
    wv.loadUrl("file:///android_asset/abc.png");  

You can WebSettings for allowing zoom controls.

Hope this will help you!!

If it worked when you loaded from resources and now it doesn't work when you load manually then I suspect that you have some problem with resource management, probably some memory leak.

Does OutOfMemoryError occur always at the start of application or it happens in later time? Is it on configuration change? Do you use static fields (if used incorrectly this often leads to memory leaks in Android application, example with explanation this fits to your case)?
Try use some profiling tools (google can help to find something useful).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!