Getting Bitmap from WebView generates OutOfMemory crash
Asked Answered
A

2

13

I have a custom WebView and I want to get a bitmap of its content (offscreen included). I used this code, which I got from here:

 public static Bitmap getBitmapFromWebviewV2(WebView webView) {
    webView.measure(View.MeasureSpec.makeMeasureSpec(
        View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED),
        View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
    webView.layout(0, 0, webView.getMeasuredWidth(),
            webView.getMeasuredHeight());
    webView.setDrawingCacheEnabled(true);
    webView.buildDrawingCache();
    Bitmap bm = Bitmap.createBitmap(webView.getMeasuredWidth(),
            webView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);

    Canvas bigcanvas = new Canvas(bm);
    Paint paint = new Paint();
    int iHeight = bm.getHeight();
    bigcanvas.drawBitmap(bm, 0, iHeight, paint);
    webView.draw(bigcanvas);
    return bm;
}

It works fine up to the point when I zoom in a lot, in which case I get OutOfMemory Crash. I tested this with the same picture (slightly zoomed and zoomed to the max) and it behaves in the same way I mentioned above.

I tried to counter this by adding

while(webView.canZoomOut()){
      webView.zoomOut();
}

at the start, but it doesn't help at all.

Adai answered 9/8, 2017 at 11:3 Comment(4)
Quick workaround - You can add android:largeHeap="true" in manifest file for more memory.Devisee
nasty workaround which won't work most of the times.... it will just delay your OOM exceptionOutclass
for me it is obvious that you wan to get too large bitmap. You can't get infinite memory in your app.Gad
The problem is that I can't reduce bitmap size after zooming in. When I use the function with initial scale it works just fine... And I already got the largeHeap on.Adai
A
0

Okay, I've cracked this one meself. The problem indeed was in the fact that the function returned the Bitmap waay before the zooming out procedure was over, so I had to delay it.

I incorporated

Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //bulk of my code
            }
        }, 1000);

which forced to change the structure of the function from public Bitmap to public void. Here's directly related thread. Despite some minor tweaks I still need to fix, the approach works like a charm

Adai answered 11/8, 2017 at 19:44 Comment(3)
So, why don't you directly get the original dimensions of your WebView before it's zoomed in and use Bitmap.createScaledBitmap(), using the original dimensions as target dimensions for the Bitmap?Catabasis
@Oleksandr Firsov , are you sure you did not get any out of memory by using handler.Sinciput
@Chestan Joshi Nope, tested it quite a few times with different images and no errors.Adai
C
-1

Quick fix:-

Set android:largeHeap="true" in your AndroidManifest.xml file.

<application
    android:name="yourapplication"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher_rounded"
    android:label="@string/app_name"
    android:largeHeap="true"
    android:roundIcon="@mipmap/ic_launcher_rounded"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">

Gud luck :)

Cellular answered 17/8, 2017 at 12:22 Comment(1)
This flag is often ignored and even in case of large heap, you still have a possibility to get OOM when creating a bitmap.Smedley

© 2022 - 2024 — McMap. All rights reserved.