Reputation: 2060
I use these two functions, slightly modified from Google's code in the Android docs to use filepaths:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromFilePath(String pathName, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(pathName, options);
}
With the idea being to use a scaled-down version of the Bitmap to be mapped onto an ImageView rather than the full-thing, which is wasteful.
mImageView.setImageBitmap(decodeSampledBitmapFromFilePath(pathToFile, 100, 100));
I implemented a thing where you press a button and it rotates to the next image, but there's still a significant lag (it takes a moment for the ImageView to populate) on my phone compared to my emulator. And then occasionally my phone app will crash and I can't replicate it on my emulator.
Is there a problem with this code I've posted above? Is there a problem with the way I am using the code?
Example:
public void reloadPic() {
new Thread(new Runnable() {
@Override
public void run() {
final Bitmap bm = decodeSampledBitmapFromFilePath(filepath, mImageViewWidth, mImageViewHeight);
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mImageView.setImageBitmap(bm);
}
});
}
}).start();
}
Upvotes: 0
Views: 311
Reputation: 93542
Your code is jumping between threads several times. First you launch a thread. Then you wait for it to be scheduled You decode on that thread. Then you post a command to the UI thread and wait for it to be scheduled. THen you post a draw command to the ui thread (that's part of what setImageBitmap does). Then you have to process any other commands that came in first. Then you actually draw the screen. There's really only 3 ways to speed this up:
1) Get rid of the thread. You shouldn't decode lots of images on the UI thread, but decoding 1 isn't too bad.
2)Store the images in the right size to begin with. This may mean creating thumbnails of the images ahead of time. Then you don't need to scale.
3)Preload your images. If there's only one button and you know what image it will load, load it before you need it, so when the button is pressed you have it ready. Wastes a bit of memory, but only 1 image worth. (This isn't a viable solution if you have a lot of possible next images).
Upvotes: 1