I am using a simple static image gallery in which i am loading atleast 28 images each of different size below 150kb.
and i noticed two issues here:
1) Slow scroll 2) Out of memory exception when i go to this activity two three - times.
Any one guide me what is the issue here and how to resolve it?
any help would be appreciated
Log Cat:
03-15 15:32:55.899: E/AndroidRuntime(14662): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:563)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:439)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.content.res.Resources.loadDrawable(Resources.java:1709)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.content.res.Resources.getDrawable(Resources.java:581)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.widget.ImageView.resolveUri(ImageView.java:501)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.widget.ImageView.setImageResource(ImageView.java:280)
03-15 15:32:55.899: E/AndroidRuntime(14662): at com.tackfu.Art$ImageAdapter.getView(Art.java:84)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.widget.AbsListView.obtainView(AbsListView.java:1515)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.widget.GridView.makeAndAddView(GridView.java:1269)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.widget.GridView.makeRow(GridView.java:315)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.widget.GridView.fillDown(GridView.java:268)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.widget.GridView.fillGap(GridView.java:235)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.widget.AbsListView.trackMotionScroll(AbsListView.java:4063)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.widget.AbsListView.onTouchEvent(AbsListView.java:2471)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.view.View.dispatchTouchEvent(View.java:3885)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:903)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
03-15 15:32:55.899: E/AndroidRuntime(14662): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1750)
03-15 15:32:55.899: E/AndroidRuntime(14662): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1135)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.app.Activity.dispatchTouchEvent(Activity.java:2096)
03-15 15:32:55.899: E/AndroidRuntime(14662): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1734)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2216)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.view.ViewRoot.handleMessage(ViewRoot.java:1887)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.os.Handler.dispatchMessage(Handler.java:99)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.os.Looper.loop(Looper.java:130)
03-15 15:32:55.899: E/AndroidRuntime(14662): at android.app.ActivityThread.main(ActivityThread.java:3687)
03-15 15:32:55.899: E/AndroidRuntime(14662): at java.lang.reflect.Method.invokeNative(Native Method)
03-15 15:32:55.899: E/AndroidRuntime(14662): at java.lang.reflect.Method.invoke(Method.java:507)
03-15 15:32:55.899: E/AndroidRuntime(14662): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
03-15 15:32:55.899: E/AndroidRuntime(14662): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
03-15 15:32:55.899: E/AndroidRuntime(14662): at dalvik.system.NativeStart.main(Native Method)
Activity Code:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.art);
GridView gridview = (GridView) findViewById(R.id.gridv
gridview.setAdapter(new ImageAdapter(this));
}
public class ImageAdapter extends BaseAdapter {
private Context mContext;
public ImageAdapter(Context c) {
mContext = c;
}
public int getCount() {
return mThumbIds.length;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}
imageView.setImageResource(mThumbIds[position]);
return imageView;
}
// references to our images
private Integer[] mThumbIds = {
R.drawable.i1, R.drawable.i2,
R.drawable.i3, R.drawable.i4,
R.drawable.i5, R.drawable.i6,
R.drawable.i7, R.drawable.i8,
R.drawable.i9, R.drawable.i10,
R.drawable.i11, R.drawable.i12,
R.drawable.i13,R.drawable.i14,
R.drawable.i15,R.drawable.i16,
R.drawable.i17,R.drawable.i18,
R.drawable.i19,R.drawable.i20,
R.drawable.i21, R.drawable.i22,
R.drawable.i23, R.drawable.i24,
R.drawable.i26, R.drawable.i28,
R.drawable.i29, R.drawable.i30
};
}
-
did you read this post stackoverflow.com/questions/1949066/…Festus Tamakloe– Festus Tamakloe2013年03月15日 10:43:06 +00:00Commented Mar 15, 2013 at 10:43
-
about the out of memory, if you launch your activity, then finish it, and then relaunch it, and get outofmemory I think you got a leak somewherelelloman– lelloman2013年03月15日 10:44:23 +00:00Commented Mar 15, 2013 at 10:44
-
i would appreciate if you point out the leak.UMAR-MOBITSOLUTIONS– UMAR-MOBITSOLUTIONS2013年03月15日 10:51:13 +00:00Commented Mar 15, 2013 at 10:51
-
I can just give you a suggestion, brutally dereference everything in activity.finish like myvar = null and call a System.gc()lelloman– lelloman2013年03月15日 10:56:44 +00:00Commented Mar 15, 2013 at 10:56
3 Answers 3
Recycle bitmaps when not in use. Use a view holder for better performance. http://www.youtube.com/watch?v=wDBM6wVEO70. I suggest you have a look at the link. Whatever applies to listview also applies to gridview and the video talks about it. The video also has a talk on view holder which is exactly what you should be using to avoid memory leaks.
There is also a talk about avoiding memory leaks at http://android-developers.blogspot.de/2009/01/avoiding-memory-leaks.html.
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html. see the section Load a Scaled Down Version into Memory
Use a MAT Analyzer to check memory leaks. http://www.youtube.com/watch?v=_CruQY55HOk.
Consider some tips at http://developer.android.com/training/articles/perf-tips.html.
2 Comments
28 images with 150KB size is about ~4MB RAM. Plus application data and it doesn't fit into small heap. You may set large heap into manifest:
android:largeHeap="true"
But this method is look as workaround, because you have unlimited memory and increasing number of images could couse again this error. You also should use lazy loading or resize images by device screen size.
3 Comments
The reason of slow scroll is quite simple. You're loading images in UI thread each time a view is created. You should delegate loading to another thread with low priority. If you wish, you can load thumbnails in UI thread to quickly show something, then load full resolution in background.
Keep in mind that Android has a lot of neat tricks to make your app nice, but you have to use them wisely. For example Android caches static views in so called Drawing Cache, but in case of ImgaeViews it's pointless, because it takes additional memory and gives nothing. Using hardware accelerated UI uses even more memory, because each view cache is drawn on power-of-two texuture. It means that 100x35px button will take 128x64x4 bytes of additional memory. Android will also try to use some kind of antialiasing, like linear texture sampler - it's nice, but takes a lot of CPU time and you may want to turn it off.
Loading images via setImageResource gives you very little control. You may want to load images by yourself so you can control loading and unloading more precisely. You can also cache images a bit. LRU cache is a good example of a class made for such use: http://developer.android.com/reference/android/util/LruCache.html . You can load current image and preload one on the left and one on the right. When a user would go back to the previous image, you will have it in memory.
Also, if you wish to use brute force, you can cache your images using NativeBuffer: http://code.google.com/p/native-buffer/ . It will force you to redesign your gallery, but it can hasten image-heavy app a lot.
Comments
Explore related questions
See similar questions with these tags.