Android ViewPager with images: memory leak/app crashes
android, android-viewpager, memory-leaks
Solution
So use
1
@Override
public Object instantiateItem(ViewGroup collection, int position)
@Override
public void destroyItem(ViewGroup collection, int position, Object view)
instead of
public Object instantiateItem(View collection, int position)
public void destroyItem(View collection, int position, Object view)
2 Tested on 6 images size 400k each work fine
@Override
public Object instantiateItem(ViewGroup collection, int position)
{
LayoutInflater inflater = (LayoutInflater) collection.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int resId = 0;
switch (position) {
case 0:
resId = R.layout.farleft;
break;
case 1:
resId = R.layout.left;
break;
case 2:
resId = R.layout.middle;
break;
case 3:
resId = R.layout.right;
break;
case 4:
resId = R.layout.farright;
break;
case 5:
resId = R.layout.farfarright;
break;
}
View view = (View) inflater.inflate(resId, null);
//get Image view from layout
//ImageView imageView = (ImageView) view.findViewById(resId);
//imageView.setImageResource(resId);
collection.addView(view, 0);
return view;
}
@Override
public void destroyItem(ViewGroup collection, int position, Object view)
{
collection.removeView((View) view);
}
3 Useful link PageAdapter
Goodluck
Problem
I am writing an app that displays a panorama picture that eventually has several markers on it to display information about certain points. As the large image crashed the app (I have also another activity in the app that is displaying a large map), I am now trying to display the panorama as a sequence of pages with ViewPager. I have managed to display the picture in 6 bits and I thought things were going well, but now the app crashes after a few swipes (about 7 to 8) as the memory runs out. I am pulling my hair out as to why that is as I thought my items would get destroyed once they are off the screen?? I am an absolute noobs and I'm so sorry if I'm being a time waster. I have spent all day reading and trying out solutions from here and elsewhere and I am none the wiser. here is my code: activity PanoramaView ``` public class PanoramaView extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.panorama); MyPagerAdapter adapter = new MyPagerAdapter(); ViewPager myPager = (ViewPager) findViewById(R.id.mysixpanelpager); myPager.setAdapter(adapter); myPager.setCurrentItem(2); } } ``` MyPagerAdapter ``` public class MyPagerAdapter extends PagerAdapter { public int getCount() { return 6; } public Object instantiateItem(View collection, int position) { LayoutInflater inflater = (LayoutInflater) collection.getContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); int resId = 0; switch (position) { case 0: resId = R.layout.farleft; break; case 1: resId = R.layout.left; break; case 2: resId = R.layout.middle; break; case 3: resId = R.layout.right; break; case 4: resId = R.layout.farright; break; case 5: resId = R.layout.farfarright; break; } //ImageView imageView = new ImageView(getApplicationContext()); //imageView.findViewById(R.id.imageView); //imageView.setImageBitmap(BitmapFactory.decodeResource(getResources(), ids[position])); View view = inflater.inflate(resId, null); ((ViewPager) collection).addView(view, 0); return view; } @Override public void destroyItem(View collection, int position, Object o) { View view = (View)o; ((ViewPager) collection).removeView(view); view = null; } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == ((View) arg1); } @Override public Parcelable saveState() { return null; } } ``` My main layout file ``` <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <android.support.v4.view.ViewPager android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/mysixpanelpager"/> </LinearLayout> ``` I promise I will be a helpful member from now on (or even more so once I actually know what I'm doing). EDIT: - In the first activity, I'm displaying an image that is 552kb. - The six images that I'm displaying in this activity (PanoramaView) are between 309 and 500kb. - I have used an allocation tracker in Eclipse and all I could see was the memory filling up but the exact data wasn't clear to me - the crash happens after displaying 7 or 8 images (basically after swiping back and fourth several times) Here is the code for farfarright.xml ``` <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageView" android:src="@drawable/panorama6" android:adjustViewBounds="true" android:contentDescription="@string/panorama" > </ImageView> </LinearLayout> ``` I have tried setting the off screen page limit which didn't help. I found this link about memory management on another post and I'll have a look at it tonight. EDIT: here is the LogCat output ``` 11-28 21:17:42.551: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 51K, 53% free 2558K/5379K, external 2002K/2137K, paused 65ms 11-28 21:17:43.261: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 1K, 53% free 2557K/5379K, external 3297K/4118K, paused 44ms 11-28 21:17:47.741: W/KeyCharacterMap(328): No keyboard for id 0 11-28 21:17:47.741: W/KeyCharacterMap(328): Using default keymap: /system/usr/keychars/qwerty.kcm.bin 11-28 21:17:49.141: D/DFSAPP(328): my button id before is 2 11-28 21:17:49.691: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 36K, 52% free 2614K/5379K, external 15576K/15708K, paused 50ms 11-28 21:17:54.571: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 12K, 52% free 2616K/5379K, external 17386K/17735K, paused 39ms 11-28 21:17:54.661: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 0K, 52% free 2616K/5379K, external 17386K/17735K, paused 61ms 11-28 21:17:54.711: I/dalvikvm-heap(328): Clamp target GC heap from 25.629MB to 24.000MB 11-28 21:17:54.711: D/dalvikvm(328): GC_FOR_MALLOC freed <1K, 52% free 2616K/5379K, external 18975K/21023K, paused 42ms 11-28 21:18:03.751: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 6K, 52% free 2616K/5379K, external 18269K/20317K, paused 46ms 11-28 21:18:03.822: I/dalvikvm-heap(328): Clamp target GC heap from 25.628MB to 24.000MB 11-28 21:18:03.852: D/dalvikvm(328): GC_FOR_MALLOC freed <1K, 52% free 2615K/5379K, external 18975K/20317K, paused 32ms 11-28 21:18:04.131: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed <1K, 52% free 2615K/5379K, external 17386K/19434K, paused 49ms 11-28 21:18:04.191: I/dalvikvm-heap(328): Clamp target GC heap from 25.628MB to 24.000MB 11-28 21:18:04.201: D/dalvikvm(328): GC_FOR_MALLOC freed 0K, 52% free 2615K/5379K, external 18975K/19434K, paused 34ms 11-28 21:18:07.301: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 1K, 52% free 2616K/5379K, external 18269K/19434K, paused 46ms 11-28 21:18:07.381: I/dalvikvm-heap(328): Clamp target GC heap from 25.801MB to 24.000MB 11-28 21:18:07.401: D/dalvikvm(328): GC_FOR_MALLOC freed <1K, 52% free 2616K/5379K, external 19152K/19434K, paused 38ms 11-28 21:18:07.611: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed <1K, 52% free 2615K/5379K, external 18159K/19434K, paused 47ms 11-28 21:18:07.681: I/dalvikvm-heap(328): Clamp target GC heap from 25.801MB to 24.000MB 11-28 21:18:07.681: D/dalvikvm(328): GC_FOR_MALLOC freed 0K, 52% free 2615K/5379K, external 19152K/19434K, paused 36ms 11-28 21:18:18.901: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 5K, 52% free 2616K/5379K, external 18269K/19434K, paused 57ms 11-28 21:18:18.972: I/dalvikvm-heap(328): Clamp target GC heap from 25.802MB to 24.000MB 11-28 21:18:18.991: D/dalvikvm(328): GC_FOR_MALLOC freed <1K, 52% free 2616K/5379K, external 19152K/19434K, paused 33ms 11-28 21:18:19.181: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 1K, 52% free 2615K/5379K, external 18159K/19434K, paused 55ms 11-28 21:18:19.251: I/dalvikvm-heap(328): Clamp target GC heap from 25.801MB to 24.000MB 11-28 21:18:19.251: D/dalvikvm(328): GC_FOR_MALLOC freed 0K, 52% free 2615K/5379K, external 19152K/19434K, paused 33ms 11-28 21:18:21.551: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 1K, 52% free 2616K/5379K, external 18975K/19434K, paused 46ms 11-28 21:18:21.581: E/dalvikvm-heap(328): 1627200-byte external allocation too large for this process. 11-28 21:18:21.621: I/dalvikvm-heap(328): Clamp target GC heap from 25.629MB to 24.000MB 11-28 21:18:21.621: E/GraphicsJNI(328): VM won't let us allocate 1627200 bytes 11-28 21:18:21.631: D/dalvikvm(328): GC_FOR_MALLOC freed 0K, 52% free 2616K/5379K, external 18975K/19434K, paused 34ms 11-28 21:18:21.641: D/AndroidRuntime(328): Shutting down VM 11-28 21:18:21.641: W/dalvikvm(328): threadid=1: thread exiting with uncaught exception (group=0x40015560) 11-28 21:18:21.732: E/AndroidRuntime(328): FATAL EXCEPTION: main 11-28 21:18:21.732: E/AndroidRuntime(328): android.view.InflateException: Binary XML file line #7: Error inflating class <unknown> 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.LayoutInflater.createView(LayoutInflater.java:518) 11-28 21:18:21.732: E/AndroidRuntime(328): at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:568) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.LayoutInflater.rInflate(LayoutInflater.java:623) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.LayoutInflater.inflate(LayoutInflater.java:408) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.LayoutInflater.inflate(LayoutInflater.java:320) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.LayoutInflater.inflate(LayoutInflater.java:276) 11-28 21:18:21.732: E/AndroidRuntime(328): at com.businesbike.dfp.MyPagerAdapter.instantiateItem(MyPagerAdapter.java:43) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:692) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.support.v4.view.ViewPager.populate(ViewPager.java:849) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.support.v4.view.ViewPager.populate(ViewPager.java:772) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.support.v4.view.ViewPager.completeScroll(ViewPager.java:1539) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.support.v4.view.ViewPager.computeScroll(ViewPager.java:1422) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.ViewGroup.drawChild(ViewGroup.java:1562) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.ViewGroup.drawChild(ViewGroup.java:1644) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.View.draw(View.java:6883) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.widget.FrameLayout.draw(FrameLayout.java:357) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.ViewGroup.drawChild(ViewGroup.java:1646) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.ViewGroup.drawChild(ViewGroup.java:1644) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.View.draw(View.java:6883) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.widget.FrameLayout.draw(FrameLayout.java:357) 11-28 21:18:21.732: E/AndroidRuntime(328): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1862) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.ViewRoot.draw(ViewRoot.java:1522) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.ViewRoot.performTraversals(ViewRoot.java:1258) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.ViewRoot.handleMessage(ViewRoot.java:1859) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.os.Handler.dispatchMessage(Handler.java:99) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.os.Looper.loop(Looper.java:123) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.app.ActivityThread.main(ActivityThread.java:3683) 11-28 21:18:21.732: E/AndroidRuntime(328): at java.lang.reflect.Method.invokeNative(Native Method) 11-28 21:18:21.732: E/AndroidRuntime(328): at java.lang.reflect.Method.invoke(Method.java:507) 11-28 21:18:21.732: E/AndroidRuntime(328): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 11-28 21:18:21.732: E/AndroidRuntime(328): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 11-28 21:18:21.732: E/AndroidRuntime(328): at dalvik.system.NativeStart.main(Native Method) 11-28 21:18:21.732: E/AndroidRuntime(328): Caused by: java.lang.reflect.InvocationTargetException 11-28 21:18:21.732: E/AndroidRuntime(328): at java.lang.reflect.Constructor.constructNative(Native Method) 11-28 21:18:21.732: E/AndroidRuntime(328): at java.lang.reflect.Constructor.newInstance(Constructor.java:415) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.view.LayoutInflater.createView(LayoutInflater.java:505) 11-28 21:18:21.732: E/AndroidRuntime(328): ... 36 more 11-28 21:18:21.732: E/AndroidRuntime(328): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget 11-28 21:18:21.732: E/AndroidRuntime(328): at android.graphics.Bitmap.nativeCreate(Native Method) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.graphics.Bitmap.createBitmap(Bitmap.java:477) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.graphics.Bitmap.createBitmap(Bitmap.java:444) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:349) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:498) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:473) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.content.res.Resources.loadDrawable(Resources.java:1709) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.content.res.TypedArray.getDrawable(TypedArray.java:601) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.widget.ImageView.<init>(ImageView.java:118) 11-28 21:18:21.732: E/AndroidRuntime(328): at android.widget.ImageView.<init>(ImageView.java:108) 11-28 21:18:21.732: E/AndroidRuntime(328): ... 39 more ``` In case someone comes across this post, here is what seems to have fixed it: I have change the code to the code from the answer below and I have also cut up my panorama picture into smaller bits so each image is now below 300kb.