Question

I send message to this handler(here I ommitted some cases) to do some operation on a bitmap and then set the bitmap on the UI. Because the operation on the bitmap is time consuming, I put it in a thread. When I finishing doing this, I set the UI in the UI thread with the method runOnUiThread.
Normally, all this runs well, but in some cases I got the following exception: java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap.
It occurs very rare, but it did happened several times.

private Handler mHandler = new Handler()
{
    @Override
    public void handleMessage(Message msg)
    {
        int what = msg.what;
        switch (what)
        {

            case VideoProtocal.COMPRESS_SUCCESS:
                state = State.COMPRESSED;
                recordBack.setVisibility(View.VISIBLE);
                recordSend.setVisibility(View.VISIBLE);
                playButton.setVisibility(View.VISIBLE);
                new Thread(){
                    @Override
                    public void run()
                    {
                        rotationBitmap();
                        runOnUiThread(new Runnable() {
                            public void run() {
                                if( null != bitmap && !bitmap.isRecycled() )
                                {
                                    Drawable drawable = new BitmapDrawable(bitmap);
                                    fristFrame.setBackgroundDrawable(drawable);
                                }
                            }
                        });
                    }
                }.start();
                mFrameCount = 0;
                getVideoSize();
                videoTime = getVideoFileTime(mp4_path) / 1000;
                timeView.setText(getString(R.string.video_count, videoTime));
                deleteTempFile();
                LogX.trace(TAG, "COMPRESS_SUCCESS");
                dismissProgress();
                break;
            default:
                break;
        }
    }

};

The method rotationBitmap() and some method it calls is shown as bellow:

private void rotationBitmap()
{
    int width = (int) (PIC_WIDTH * FusionField.currentDensity);
    int height = (int) (PIC_HIGHT * FusionField.currentDensity);
    Bitmap bmTemp = bitmap;
    bitmap = CommonUtil.resizeImage(bitmap, width, height);

    if (bmTemp != null && !bmTemp.isRecycled() && bmTemp != bitmap)
    {
        bmTemp.recycle();
        bmTemp = null;
    }

    rotate(bitmap, rotationAngle());

    CommonUtil.checkMysoftStage(FusionCode.videoThumbnail);
    String videoName = CommonUtil.getUniqueName(".jpg", FusionCode.videoName);
    jpg_path = FusionCode.videoThumbnail + "/" + videoName;
    try
    {
        FileOutputStream fos = new FileOutputStream(jpg_path);
        if (bitmap != null)
        {
            bitmap.compress(CompressFormat.JPEG, 50, fos);
        }
        fos.close();
    }
    catch (FileNotFoundException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}


private Bitmap rotate(Bitmap b, int degrees)
{
    if (degrees != 0 && b != null)
    {
        Matrix m = new Matrix();
        m.setRotate(degrees, (float) b.getWidth() / 2, (float) b.getHeight() / 2);
        try
        {
            bitmap = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, true);
        }
        catch (OutOfMemoryError ex)
        {
            // TODO Auto-generated catch block
            ex.printStackTrace();
        }
    }
    return b;
}

From the code, the problem must ocuured in this statement:

Drawable drawable = new BitmapDrawable(bitmap);

but according to the code context, the bitmap should't be null or recycled, that'really strange.

I have been hanging around this issue nearly two days and can't figure it out what the problem is, but the issue does exists. Could anybody give me some suggestions? Any response is appreciated! Thanks!

By the way, when I try to the RuntimeException like this, this kind of exception can't be catched, WHY?

try
{
    bitmap.recycle();
    Drawable drawable = new BitmapDrawable(bitmap);
    fristFrame.setBackgroundDrawable(drawable);
}
catch (RuntimeException e)
{
    e.printStackTrace();
}
Was it helpful?

Solution

Okey, let me answer my question. The problem occurs because the VideoProtocal.COMPRESS_SUCCESS was received by mHandler twice. It has multi-thread there, so at some point, the "used a recycled bitmap" problem occurs. As to why twice message was received, er... that's my fault use of timer task.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top