0

i have a FragmentPagerAdapter which causes outofmemory error and crush in the handsets since it leaks memory ,there is no room for a new activity. Tablets can handle it works fine but not on the handsets.i have tried the code below, but it couldn't solve it. How do i clean a FragmentPagerAdapter on destroy?

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    try {
        FragmentManager manager = ((Fragment)object).getFragmentManager();
        FragmentTransaction trans = manager.beginTransaction();
        trans.remove((Fragment)object).commit();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }


}

and this is my log

05-12 06:35:32.130: E/AndroidRuntime(1493): FATAL EXCEPTION: main
05-12 06:35:32.130: E/AndroidRuntime(1493): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.company.project/com.company.project.ProjectMainActivity}: android.view.InflateException: Binary XML file line #156: Error inflating class <unknown>
05-12 06:35:32.130: E/AndroidRuntime(1493):     at     android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.app.ActivityThread.access$1500(ActivityThread.java:117)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.os.Handler.dispatchMessage(Handler.java:99)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.os.Looper.loop(Looper.java:130)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.app.ActivityThread.main(ActivityThread.java:3683)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at java.lang.reflect.Method.invokeNative(Native Method)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at java.lang.reflect.Method.invoke(Method.java:507)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at dalvik.system.NativeStart.main(Native Method)
05-12 06:35:32.130: E/AndroidRuntime(1493): Caused by: android.view.InflateException: Binary XML file line #156: Error inflating class <unknown>
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.createView(LayoutInflater.java:518)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:570)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:623)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:626)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:626)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:626)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.inflate(LayoutInflater.java:408)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:207)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.app.Activity.setContentView(Activity.java:1657)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at com.company.project.ProjectMainActivity.onCreate(ProjectMainActivity.java:57)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
05-12 06:35:32.130: E/AndroidRuntime(1493):     ... 11 more
05-12 06:35:32.130: E/AndroidRuntime(1493): Caused by: java.lang.reflect.InvocationTargetException
05-12 06:35:32.130: E/AndroidRuntime(1493):     at java.lang.reflect.Constructor.constructNative(Native Method)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at java.lang.reflect.Constructor.newInstance(Constructor.java:415)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.view.LayoutInflater.createView(LayoutInflater.java:505)
05-12 06:35:32.130: E/AndroidRuntime(1493):     ... 24 more
05-12 06:35:32.130: E/AndroidRuntime(1493): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:460)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.content.res.Resources.loadDrawable(Resources.java:1709)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.content.res.Resources.getDrawable(Resources.java:581)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:162)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:787)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.graphics.drawable.Drawable.createFromXml(Drawable.java:728)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.content.res.Resources.loadDrawable(Resources.java:1694)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.widget.ImageView.<init>(ImageView.java:118)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at android.widget.ImageView.<init>(ImageView.java:108)
05-12 06:35:32.130: E/AndroidRuntime(1493):     at com.company.project.widget.AspectRatioImageView.<init>(AspectRatioImageView.java:17)
05-12 06:35:32.130: E/AndroidRuntime(1493):     ... 27 more

i am doing revision of a project.in the previous version its done by view pager and this has been added to the adapter. i thick i need to convert this for fragmentpageradapter.

 @Override
    public void destroyItem(View collection, int position, Object o) {
        View view = (View)o;
        ((ViewPager) collection).removeView(view);
        view = null;
    }
Alp
  • 1,863
  • 1
  • 20
  • 38

2 Answers2

2

OutOfMemoryError doesn't necessarily mean a memory leak.

Your stack trace shows

java.lang.OutOfMemoryError: bitmap size exceeds VM budget

which means you're trying to load a bitmap and there isn't enough memory.

You should learn how to display bitmaps efficiently.

Also with a FragmentPagerAdapter we usually don't override destroyItem().

Your adapter should look like the following:

public static class MyPagerAdapter extends FragmentPagerAdapter {
    private static final int COUNT = 5;

    public MyPagerAdapter(FragmentManager fragmentManager) {
        super(fragmentManager);
    }

    @Override
    public int getCount() {
        return COUNT;
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
        case 0:
            return new FragmentA();
        case 1:
            return new FragmentB();
        case 2:
            return new FragmentC();
        case 3:
            return new FragmentD();
        case 4:
            return new FragmentE();    
        default:
            return null;
        }
    }

}
Benito Bertoli
  • 25,285
  • 12
  • 54
  • 61
  • if i go to main activity directly from start,it works.but if i go main activity from intro activity which i use my fragmentpageradapter it crushes.i think this means it leaks memory. – Alp May 12 '14 at 06:51
  • What are you displaying in your fragments? how many fragments do you have and what is the viewpager's offscreen limit? – Benito Bertoli May 12 '14 at 06:55
  • i have 5 fragments one of them getting json by AsyncHttpClient than parsing it to data.converts to objects and displays in the list view elements.rest just shows it layout and goes main activity on a button click. – Alp May 12 '14 at 07:05
  • When you start your second activity, the first one is still using part of the available memory. So you should also make sure you're not trying to load large bitmaps in the second activity. – Benito Bertoli May 12 '14 at 07:30
  • Are you loading large images in main activity? – Benito Bertoli May 12 '14 at 07:45
  • not large images no. most of them are 8 kbs. and main images is around 200kb. – Alp May 12 '14 at 07:53
  • 1
    The problem isn't with the image's size on disk. It's with the size in memory. It is relative to the dimension (resolution). Each pixel needs 32 bits. So a 1000x1000 px image might have a 200KB size on disk but needs 4MB memory. Make sure you're loading images efficiently. – Benito Bertoli May 12 '14 at 08:03
  • what you say is true but even if that happens i would still need to clear the heap by deleting adapter items to make more room for new images. – Alp May 12 '14 at 08:15
0

FragmentStatePagerAdapter can be solution for some examples which has similarity to this solution . FragmentStatePagerAdapter only shows 1 fragment and deletes other fragments so heap size stay at minimum.If fragments doesn't trading data between them unlike my application , i would suggest use FragmentStatePagerAdapter. For me this is not case. i need to keep some fragments. When i go to my main activity form intro activity all fragments are staying still but not all fragments are necessary.My solution has based on fragmentstatepageradapter solution. There maybe a better solution but by reducing fragment number that i keep in heap,i have solved crush problem.

myPager.setOffscreenPageLimit(3);//previous was 5
Alp
  • 1,863
  • 1
  • 20
  • 38