Вопрос

background

starting from API 11, you can re-use bitmaps when you decode new ones, so that the decoder won't need to re-create totally new large objects.

this is done using something like this code (taken from this tutorial) :

mCurrentBitmap = Bitmap.createBitmap(imageWidth,imageHeight,Bitmap.Config.ARGB_8888);
bitmapOptions.inJustDecodeBounds = false;
bitmapOptions.inBitmap = mCurrentBitmap;
bitmapOptions.inSampleSize = 1;
mCurrentBitmap = BitmapFactory.decodeResource(getResources(),imageResId, bitmapOptions);

the advantage is quite obvious: using less memory in some cases, getting less pressure on the GC, and having a better performance because you don't need to create a lot more large objects.

the only catch is that both images must be of the same size and config.

the problem

even though the code works perfectly fine with resources in the project itself (in the res folder), i seem to always get the next error when handling image files i've put into the internal storage :

java.lang.IllegalArgumentException: Problem decoding into existing bitmap

i've tried multiple different flags for the bitmap options:

bitmapOptions.inPurgeable = true;
bitmapOptions.inInputShareable = true;
bitmapOptions.inMutable = true;
bitmapOptions.inScaled = false;
bitmapOptions.inSampleSize = 1;
bitmapOptions.inPreferredConfig = Config.RGB_565; //i've set the created bitmap to be of this type too, of course

i've also tried both decodeFile and decodeStream for the BitmapFactory.

here's a sample code to show there is a problem (based on the sample i've written about) :

@Override
public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_bitmap_allocation);

    final int[] imageIDs = { R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d, R.drawable.e, R.drawable.f };

    final CheckBox checkbox = (CheckBox) findViewById(R.id.checkbox);
    final TextView durationTextview = (TextView) findViewById(R.id.loadDuration);
    final ImageView imageview = (ImageView) findViewById(R.id.imageview);

    // Create bitmap to be re-used, based on the size of one of the bitmaps
    mBitmapOptions = new BitmapFactory.Options();
    mBitmapOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(getResources(), R.drawable.a, mBitmapOptions);
    mCurrentBitmap = Bitmap.createBitmap(mBitmapOptions.outWidth, mBitmapOptions.outHeight, Bitmap.Config.ARGB_8888);
    mBitmapOptions.inJustDecodeBounds = false;
    mBitmapOptions.inBitmap = mCurrentBitmap;
    mBitmapOptions.inSampleSize = 1;
    mBitmapOptions.inPreferredConfig = Config.ARGB_8888;
    BitmapFactory.decodeResource(getResources(), R.drawable.a, mBitmapOptions);
    imageview.setImageBitmap(mCurrentBitmap);

    // When the user clicks on the image, load the next one in the list
    imageview.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(final View v) {
            mCurrentIndex = (mCurrentIndex + 1) % imageIDs.length;
            Options bitmapOptions = new Options();
            bitmapOptions.inPreferredConfig = Config.ARGB_8888;
            if (checkbox.isChecked()) {
                // Re-use the bitmap by using BitmapOptions.inBitmap
                bitmapOptions = mBitmapOptions;
                bitmapOptions.inBitmap = mCurrentBitmap;
            }
            final long startTime = System.currentTimeMillis();
            //
            File tempFile = null;
            try {
                tempFile = File.createTempFile("temp", ".webp", getApplicationContext().getCacheDir());
                FileOutputStream fileOutputStream;
                final Bitmap bitmap = BitmapFactory.decodeResource(getResources(), imageIDs[mCurrentIndex]);
                bitmap.compress(CompressFormat.WEBP, 100, fileOutputStream = new FileOutputStream(tempFile));
                fileOutputStream.flush();
                fileOutputStream.close();
            final InputStream inputStream = new FileInputStream(tempFile);
            mCurrentBitmap = BitmapFactory.decodeStream(inputStream,null,bitmapOptions);
            inputStream.close();
            } catch (final IOException e1) {
                e1.printStackTrace();
            }
            imageview.setImageBitmap(mCurrentBitmap);

            // One way you can see the difference between reusing and not is through the
            // timing reported here. But you can also see a huge impact in the garbage
            // collector if you look at logcat with and without reuse. Avoiding garbage
            // collection when possible, especially for large items like bitmaps,
            // is always a good idea.
            durationTextview.setText("Load took " + (System.currentTimeMillis() - startTime));
        }
    });
}

the question

why do i keep getting this error, and how can i fix it?

i've found some similar questions, but none had an answer.

Это было полезно?

Решение

it seems that the problem with this cool tip when using webP files.

i just need to use either jpg or png.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top