pbm
pbm

Reputation: 5371

BitmapFactory.decodeStream from Assets sometimes fails on Android 7

I have just moved from androidTargetSdk=23 to androidTargetSdk=24. I'm also using JDK 1.8 and sourceCompatibility="1.7" and targetCompatibility="1.7".

The following existing code for decoding assets malfunctions on Android Studio's emulator Galaxy_S6_API_24 and Genymotion API 24 emulator (but runs just fine on real devices running API 19 and 21) .

myInputStream = getActivity().getAssets().open("images/" + imageName);
BitmapFactory.Options opts = new BitmapFactory.Options();

// Find the size of the image
// (http://developer.android.com/training/displaying-bitmaps/load-bitmap.html)
opts.inJustDecodeBounds = true;
BitmapFactory.decodeStream(myInputStream, null, opts);

// For debugging this issue to keep it simple I've stopped calling calculateInSampleSize()
//opts.inSampleSize = ImageUtils.calculateInSampleSize(opts, width, height);
opts.inSampleSize = 1;
opts.inJustDecodeBounds = false;

bm = BitmapFactory.decodeStream(myInputStream, null, opts);
imageView.setImageBitmap( bm );

When debugging this code myInputStream is not null, so the asset is found. Method decodeStream() returns null.

To debug further I changed the code to the following. This code works - BitmapFactory.decodeStream() returns a valid bitmap.

myInputStream = getActivity().getAssets().open("images/" + imageName);
BitmapFactory.Options opts = new BitmapFactory.Options();

// Find the size of the image
// (http://developer.android.com/training/displaying-bitmaps/load-bitmap.html)
opts.inJustDecodeBounds = true;
//BitmapFactory.decodeStream(myInputStream, null, opts);

// For debugging this issue to keep it simple I've stopped calling calculateInSampleSize()
//opts.inSampleSize = ImageUtils.calculateInSampleSize(opts, width, height);
opts.inSampleSize = 1;
opts.inJustDecodeBounds = false;

bm = BitmapFactory.decodeStream(myInputStream, null, opts);
imageView.setImageBitmap( bm );

The only difference between the failing code at the top and the running code directly above is that I've commented out the 1st call to BitmapFactory.decodeStream().

To debug this further I simplified the code. This works:

myInputStream = getActivity().getAssets().open("images/" + imageName);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 1;
bm = BitmapFactory.decodeStream(myInputStream, null, opts);
imageView.setImageBitmap( bm );

But this fails to display an image (note I've called decodeStream twice below):

myInputStream = getActivity().getAssets().open("images/" + imageName);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 1;
bm = BitmapFactory.decodeStream(myInputStream, null, opts);
bm = BitmapFactory.decodeStream(myInputStream, null, opts);
imageView.setImageBitmap( bm );

This also fails:

myInputStream = getActivity().getAssets().open("images/" + imageName);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 1;
bm = BitmapFactory.decodeStream(myInputStream, null, opts);
BitmapFactory.Options opts2 = new BitmapFactory.Options();
opts2.inSampleSize = 1;
bm = BitmapFactory.decodeStream(myInputStream, null, opts2);
imageView.setImageBitmap( bm );

With the debugger I've stepped into the API 24 source for BitMapFactory.decodeStream(). The problem is due to the call to nativeDecodeAsset() failing. It always fails the 2nd time it is called with the same input asset. My guess is that I'm using the correct native library but it has a bug or somehow the library I'm using is wrong.

As I mentioned previously, I do not see this problem on real devices running API 19 and 21. I see it only on the Android Studio's emulator Galaxy_S6_API_24 and and the Genymotion API 24 emulator.

Its unclear to me how to debug this. Where can I get the source code for the native library matching my build? Can you suggest a solution or what more I should check to solve this? I'd like to prove my code works on Android 7.0 without having to use a real device!

Upvotes: 1

Views: 858

Answers (2)

pbm
pbm

Reputation: 5371

Once you've read from an input stream (e.g. in BitmapFatory.decodeStream) you cannot back-up again to the start of the stream again. Think of it like reading from a byte array where the read index into the array is not available to you - each time you read you get the bytes after the previous time you read.

When input stream is initialised to the start of an asset via myInputStream = getActivity().getAssets().open("images/" + imageName), once you've called BitmapFatory.decodeStream() the input stream is effectively pointing beyond the asset. If you try to use it again it wont work. In this case you must initialise the input stream before each call to BitmapFatory.decodeStream().

Upvotes: 0

Amirkhm
Amirkhm

Reputation: 1096

This is not a problem with android; The input stream becomes null after you use it inside method decodestream(); If you want to use the inputstream for more than once, you should reset it each time using it's .reset() functions.

Upvotes: 1

Related Questions