Reputation: 9361
This app was working with no problems but was too slow. It was running everything on the one UI thread, when a page loaded with many images in gridView it would take a long delay before the page would load. I fixed this problem using code from the android docs called "Processing Bitmaps Off the UI Thread"
Using the code it now loads the gridview page vary fast and after you can see it loading each small bitmap image one by one in a separate background thread.
In this code that uses AsyncTask for the multi-threading part it also uses a couple of methods to reduce the image size to eliminate out of memory errors. The same image reduction methods i used in the previous single threaded version of this program. No matter how big the image it should not be bigger than 200dp by 200dp set by the image reduction method. It works in the older version of the app without multi-threading, and it looks ok for the most part in the new version of the app. but there is a strange problem.
I am now getting out of memory errors connected to the BitmapFactory decode method.
How this happens is I started testing the app with many smaller images and put one huge one in there about 10,000 X 10,000 pixel bitmap. That should not be causing problems because the images are being reduced by using bitmap factory options.
The errors don't happen right away. The app works fine for a while but after moving around and going back an forth between activities. After 3 to 5 minutes it will crash.
Is anyone else having problems like this? And can you offer any ideas that might be the cause I could check out? Or help me to start looking in the right direction?
The image reducing code is shown here below and under that is the logcat output.
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private String data = "";
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
// Decode image in background.
@Override
protected Bitmap doInBackground(String... params) {
data = params[0];
// return imageProcessor(data);
return decodeSampledBitmapFromResource(data, 100, 100);
}
// Once complete, see if ImageView is still around and set bitmap.
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}// end BitmapWorkerTask extends AsyncTask class
public static Bitmap decodeSampledBitmapFromResource(String fileName, int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(fileName, options);
}//end decodeSampledBitmapfromresource method
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) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}// end calculateInSampleSize method
Logcat
17:52:28.340: E/AndroidRuntime(7812): FATAL EXCEPTION: main
17:52:28.340: E/AndroidRuntime(7812): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.v.splitter/com.v.splitter.AudioViewer}: android.view.InflateException: Binary XML file line #63: Error inflating class <unknown>
17:52:28.340: E/AndroidRuntime(7812): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)
17:52:28.340: E/AndroidRuntime(7812): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
17:52:28.340: E/AndroidRuntime(7812): at android.app.ActivityThread.access$600(ActivityThread.java:123)
17:52:28.340: E/AndroidRuntime(7812): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
17:52:28.340: E/AndroidRuntime(7812): at android.os.Handler.dispatchMessage(Handler.java:99)
17:52:28.340: E/AndroidRuntime(7812): at android.os.Looper.loop(Looper.java:137)
17:52:28.340: E/AndroidRuntime(7812): at android.app.ActivityThread.main(ActivityThread.java:4424)
17:52:28.340: E/AndroidRuntime(7812): at java.lang.reflect.Method.invokeNative(Native Method)
17:52:28.340: E/AndroidRuntime(7812): at java.lang.reflect.Method.invoke(Method.java:511)
17:52:28.340: E/AndroidRuntime(7812): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
17:52:28.340: E/AndroidRuntime(7812): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
17:52:28.340: E/AndroidRuntime(7812): at dalvik.system.NativeStart.main(Native Method)
17:52:28.340: E/AndroidRuntime(7812): Caused by: android.view.InflateException: Binary XML file line #63: Error inflating class <unknown>
17:52:28.340: E/AndroidRuntime(7812): at android.view.LayoutInflater.createView(LayoutInflater.java:606)
17:52:28.340: E/AndroidRuntime(7812): at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
17:52:28.340: E/AndroidRuntime(7812): at android.view.LayoutInflater.onCreateView(LayoutInflater.java:653)
17:52:28.340: E/AndroidRuntime(7812): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:678)
17:52:28.340: E/AndroidRuntime(7812): at android.view.LayoutInflater.rInflate(LayoutInflater.java:739)
17:52:28.340: E/AndroidRuntime(7812): at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
17:52:28.340: E/AndroidRuntime(7812): at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
17:52:28.340: E/AndroidRuntime(7812): at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
17:52:28.340: E/AndroidRuntime(7812): at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:255)
17:52:28.340: E/AndroidRuntime(7812): at android.app.Activity.setContentView(Activity.java:1835)
17:52:28.340: E/AndroidRuntime(7812): at com.v.splitter.AudioViewer.onCreate(AudioViewer.java:63)
17:52:28.340: E/AndroidRuntime(7812): at android.app.Activity.performCreate(Activity.java:4465)
17:52:28.340: E/AndroidRuntime(7812): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
17:52:28.340: E/AndroidRuntime(7812): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
17:52:28.340: E/AndroidRuntime(7812): ... 11 more
17:52:28.340: E/AndroidRuntime(7812): Caused by: java.lang.reflect.InvocationTargetException
17:52:28.340: E/AndroidRuntime(7812): at java.lang.reflect.Constructor.constructNative(Native Method)
17:52:28.340: E/AndroidRuntime(7812): at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
17:52:28.340: E/AndroidRuntime(7812): at android.view.LayoutInflater.createView(LayoutInflater.java:586)
17:52:28.340: E/AndroidRuntime(7812): ... 24 more
12-17:52:28.340: E/AndroidRuntime(7812): Caused by: java.lang.OutOfMemoryError
17:52:28.340: E/AndroidRuntime(7812): at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
17:52:28.340: E/AndroidRuntime(7812): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:483)
17:52:28.340: E/AndroidRuntime(7812): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:351)
17:52:28.340: E/AndroidRuntime(7812): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:773)
17:52:28.340: E/AndroidRuntime(7812): at android.content.res.Resources.loadDrawable(Resources.java:1937)
17:52:28.340: E/AndroidRuntime(7812): at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
17:52:28.340: E/AndroidRuntime(7812): at android.view.View.<init>(View.java:2785)
17:52:28.340: E/AndroidRuntime(7812): at android.view.View.<init>(View.java:2722)
17:52:28.340: E/AndroidRuntime(7812): at android.view.ViewGroup.<init>(ViewGroup.java:379)
17:52:28.340: E/AndroidRuntime(7812): at android.widget.RelativeLayout.<init>(RelativeLayout.java:174)
17:52:28.340: E/AndroidRuntime(7812): ... 27 more
Upvotes: 0
Views: 849
Reputation: 4725
A 10,000x10,000 image still needs to be loaded for BitmapFactory to resize. I'd suggest making that image smaller.
Anyway, if you're using a lot of Bitmaps, make sure to recycle them when you're finished with them. They consume native resources that garbage collection takes a while to get to.
bitmap.recycle();
Just make sure not to use the Bitmap after recycling because an exception will be thrown.
Upvotes: 2