سؤال

I'm running into OutOfMemoryErrors in an app that I'm working on and I'm having difficulty figuring out how to fix it and what exactly the issue is. I'm using the FragmentStatePagerAdapter, since that seemed like the best/recommended alternative. I'm also using Universal Image Loader v.1.8.4. What happens is that when you page through the views, the heap grows and eventually runs out of memory. Here's a little sample output:

05-06 14:38:23.096: D/dalvikvm(29322): GC_CONCURRENT freed 187K, 5% free 7532K/7868K, paused 7ms+13ms, total 37ms
05-06 14:38:23.176: D/dalvikvm(29322): GC_FOR_ALLOC freed 96K, 4% free 7656K/7920K, paused 17ms, total 17ms
05-06 14:38:23.206: D/dalvikvm(29322): GC_FOR_ALLOC freed <1K, 4% free 8234K/8500K, paused 15ms, total 15ms
05-06 14:38:23.246: D/dalvikvm(29322): GC_CONCURRENT freed 4K, 3% free 8262K/8500K, paused 5ms+5ms, total 31ms
05-06 14:38:23.276: D/dalvikvm(29322): GC_FOR_ALLOC freed 29K, 3% free 8289K/8500K, paused 20ms, total 25ms
05-06 14:38:23.286: D/dalvikvm(29322): GC_FOR_ALLOC freed <1K, 3% free 9342K/9556K, paused 15ms, total 15ms
05-06 14:38:23.316: D/dalvikvm(29322): GC_CONCURRENT freed 27K, 3% free 9327K/9556K, paused 3ms+2ms, total 22ms
05-06 14:38:24.626: D/dalvikvm(29322): GC_FOR_ALLOC freed 83K, 3% free 9462K/9696K, paused 15ms, total 16ms
05-06 14:38:24.646: D/dalvikvm(29322): GC_FOR_ALLOC freed 3K, 3% free 10201K/10440K, paused 16ms, total 16ms
05-06 14:38:24.666: D/dalvikvm(29322): GC_CONCURRENT freed 3K, 3% free 10214K/10440K, paused 3ms+3ms, total 26ms
05-06 14:38:24.976: D/dalvikvm(29322): GC_FOR_ALLOC freed 68K, 3% free 10291K/10508K, paused 16ms, total 17ms
05-06 14:38:24.986: D/dalvikvm(29322): GC_FOR_ALLOC freed <1K, 2% free 11297K/11516K, paused 15ms, total 15ms
05-06 14:38:25.016: D/dalvikvm(29322): GC_CONCURRENT freed 8K, 2% free 11305K/11516K, paused 3ms+4ms, total 24ms
05-06 14:38:25.346: D/dalvikvm(29322): GC_CONCURRENT freed 74K, 2% free 12458K/12680K, paused 2ms+3ms, total 23ms
05-06 14:38:25.976: D/dalvikvm(29322): GC_FOR_ALLOC freed 151K, 3% free 13485K/13792K, paused 22ms, total 22ms
05-06 14:38:26.276: D/dalvikvm(29322): GC_CONCURRENT freed 95K, 2% free 15384K/15636K, paused 3ms+3ms, total 26ms
05-06 14:38:27.196: D/dalvikvm(29322): GC_FOR_ALLOC freed 222K, 3% free 17111K/17484K, paused 24ms, total 24ms
05-06 14:38:28.446: D/dalvikvm(29322): GC_FOR_ALLOC freed 247K, 2% free 19784K/20180K, paused 22ms, total 22ms
05-06 14:38:29.396: D/dalvikvm(29322): GC_FOR_ALLOC freed 248K, 2% free 23137K/23540K, paused 23ms, total 24ms
05-06 14:38:30.976: D/dalvikvm(29322): GC_FOR_ALLOC freed 391K, 2% free 27770K/28308K, paused 29ms, total 29ms
05-06 14:38:33.366: D/dalvikvm(29322): GC_CONCURRENT freed 516K, 2% free 33964K/34628K, paused 3ms+6ms, total 45ms
05-06 14:38:36.126: D/dalvikvm(29322): GC_FOR_ALLOC freed 608K, 2% free 41164K/41920K, paused 37ms, total 37ms
05-06 14:38:38.396: D/dalvikvm(29322): GC_CONCURRENT freed 598K, 2% free 48739K/49484K, paused 4ms+10ms, total 59ms
05-06 14:38:41.496: D/dalvikvm(29322): GC_CONCURRENT freed 723K, 2% free 56176K/57044K, paused 2ms+13ms, total 71ms
05-06 14:38:41.496: D/dalvikvm(29322): WAIT_FOR_CONCURRENT_GC blocked 62ms
05-06 14:38:45.176: I/dalvikvm-heap(29322): Clamp target GC heap from 69.393MB to 64.000MB
05-06 14:38:45.176: D/dalvikvm(29322): GC_FOR_ALLOC freed 597K, 2% free 62724K/63476K, paused 56ms, total 56ms
05-06 14:38:45.936: I/dalvikvm-heap(29322): Clamp target GC heap from 71.379MB to 64.000MB
05-06 14:38:45.936: D/dalvikvm(29322): GC_FOR_ALLOC freed 216K, 1% free 64758K/65412K, paused 50ms, total 50ms
05-06 14:38:45.996: I/dalvikvm-heap(29322): Clamp target GC heap from 71.338MB to 64.000MB
05-06 14:38:45.996: D/dalvikvm(29322): GC_BEFORE_OOM freed 43K, 2% free 64714K/65412K, paused 60ms, total 60ms
05-06 14:38:46.336: I/dalvikvm-heap(29322): Clamp target GC heap from 71.462MB to 64.000MB
05-06 14:38:46.336: D/dalvikvm(29322): GC_FOR_ALLOC freed 139K, 2% free 64841K/65500K, paused 52ms, total 52ms
05-06 14:38:46.396: I/dalvikvm-heap(29322): Clamp target GC heap from 71.462MB to 64.000MB
05-06 14:38:46.396: D/dalvikvm(29322): GC_BEFORE_OOM freed <1K, 2% free 64840K/65500K, paused 62ms, total 62ms

First off, yes, I've done a lot of digging on stackoverflow and other sites trying to figure out what the problem is. I've tried various solutions that recycle bitmaps, use unbindDrawables, and try to remove views/recycle bitmaps in destroyItem() of the PagerAdapter...to name a few. NONE of these have worked for me (I can provide more details about what I've done if needed).

So, in a nutshell, I'm able to reproduce my issue using a modified version of this example (From Google Developers site). I modified it a bit to work with Universal Image Loader v.1.8.4 and also made the layout a little more complex to somewhat mimic what I have in the app I'm working on. The reason I changed the layout was because everything seems to work fine if you make the layout really simple and only include an image and some text fields. When the layout gets more complex and when you start to add more pages to the adapter you start to run into OOM errors. However, I'm not sure sure it's an issue with the layout or UIL...read on...

I've run MAT in Eclipse and here's what it says under the only Leak Suspects report (only 1 problem):

One instance of "com.example.android.animationsdemo.ScreenSlideActivity$ScreenSlidePagerAdapter"
loaded by "dalvik.system.PathClassLoader @ 0x42124098" occupies 56,171,048 (86.62%) bytes.
The memory is accumulated in one instance of "java.lang.Object[]" loaded by "<system class loader>".

Keywords
java.lang.Object[]
dalvik.system.PathClassLoader @ 0x42124098
com.example.android.animationsdemo.ScreenSlideActivity$ScreenSlidePagerAdapter

If you then check out the Dominator Tree and expand the ScreenSlidePagerAdapter, it shows 25 of 59 entries for the following:

> java.util.ArrayList @ 0x4216ccf0
    > java.lang.Object[60] @ 0x44b07d8
        > android.app.Fragment$SavedState @ 0x439bd038

I'm no expert with this tool and I'm pretty new to Android and development in general, but it looks like the saved state for the adapter isn't getting purged correctly and that's what's causing the OOM issue (it's saving the entire view, not just bitmaps). However, I haven't been able to figure out how to clear/release/destroy/whatever the saved state data or if I'm doing something wrong somewhere else. I did run into one post that said to try using .setSaveEnabled(false), but that didn't make any difference, I still got the OOM errors. I even tried overriding saveState() for the adapter and returning null and that didn't make a difference either.

Here's relevant code/config info that should hopefully answer most of the questions:

For UIL, I'm just using the default config, since changes didn't seem to make a difference:

imageLoader.init(ImageLoaderConfiguration.createDefault(this));

ScreenSlideActivity:

public class ScreenSlideActivity extends FragmentActivity {
    /**
     * The number of pages (wizard steps) to show in this demo.
     */
    private static final String[] IMAGES = Constants.IMAGES;

    /**
     * The pager widget, which handles animation and allows swiping horizontally to access previous
     * and next wizard steps.
     */
    private ViewPager mPager;

    /**
     * The pager adapter, which provides the pages to the view pager widget.
     */
    private PagerAdapter mPagerAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_screen_slide);

        // Instantiate a ViewPager and a PagerAdapter.
        mPager = (ViewPager) findViewById(R.id.pager);
        mPagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager(), IMAGES);

        mPager.setSaveEnabled(false); // <--- THIS DOESN'T APPEAR TO MAKE ANY DIFFERENCE

        mPager.setAdapter(mPagerAdapter);
        mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                // When changing pages, reset the action bar actions since they are dependent
                // on which page is currently active. An alternative approach is to have each
                // fragment expose actions itself (rather than the activity exposing actions),
                // but for simplicity, the activity provides the actions in this sample.
                invalidateOptionsMenu();
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.activity_screen_slide, menu);

        menu.findItem(R.id.action_previous).setEnabled(mPager.getCurrentItem() > 0);

        // Add either a "next" or "finish" button to the action bar, depending on which page
        // is currently selected.
        MenuItem item = menu.add(Menu.NONE, R.id.action_next, Menu.NONE,
                (mPager.getCurrentItem() == mPagerAdapter.getCount() - 1)
                        ? R.string.action_finish
                        : R.string.action_next);
        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                // Navigate "up" the demo structure to the launchpad activity.
                // See http://developer.android.com/design/patterns/navigation.html for more.
                NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class));
                return true;

            case R.id.action_previous:
                // Go to the previous step in the wizard. If there is no previous step,
                // setCurrentItem will do nothing.
                mPager.setCurrentItem(mPager.getCurrentItem() - 1);
                return true;

            case R.id.action_next:
                // Advance to the next step in the wizard. If there is no next step, setCurrentItem
                // will do nothing.
                mPager.setCurrentItem(mPager.getCurrentItem() + 1);
                return true;
        }

        return super.onOptionsItemSelected(item);
    }

    /**
     * A simple pager adapter that represents 5 {@link ScreenSlidePageFragment} objects, in
     * sequence.
     */
    private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
        String[] mImages;
        public ScreenSlidePagerAdapter(FragmentManager fm, String[] images) {
            super(fm);
            this.mImages = images;
        }

        @Override
        public Fragment getItem(int position) {
            return ScreenSlidePageFragment.create(position, mImages);
        }

        @Override
        public int getCount() {
            return IMAGES.length;
        }
    }
}

ScreenSlidePageFragment, called by above activity:

public class ScreenSlidePageFragment extends Fragment {

    // Universal Image Loader
    private DisplayImageOptions mOptions;
    protected ImageLoader mImageLoader = ImageLoader.getInstance();

    /**
     * The argument key for the page number this fragment represents.
     */
    public static final String ARG_PAGE = "page";

    public static final String ARG_IMAGES = "images";

    /**
     * The fragment's page number, which is set to the argument value for {@link #ARG_PAGE}.
     */
    private int mPageNumber;
    private String[] mImages;

    /**
     * Factory method for this fragment class. Constructs a new fragment for the given page number.
     */
    public static ScreenSlidePageFragment create(int pageNumber, String[] images) {
        ScreenSlidePageFragment fragment = new ScreenSlidePageFragment();
        Bundle args = new Bundle();
        args.putInt(ARG_PAGE, pageNumber);
        args.putStringArray(ARG_IMAGES, images);
        fragment.setArguments(args);
        return fragment;
    }

    public ScreenSlidePageFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPageNumber = getArguments().getInt(ARG_PAGE);
        mImages = getArguments().getStringArray(ARG_IMAGES);

        mOptions = new DisplayImageOptions.Builder()
        .showImageForEmptyUri(R.drawable.ic_empty)
        .showImageOnFail(R.drawable.ic_error)
        .resetViewBeforeLoading()
        .cacheOnDisc()
        .imageScaleType(ImageScaleType.EXACTLY)
        .bitmapConfig(Bitmap.Config.RGB_565)
        .displayer(new SimpleBitmapDisplayer())
        .build();

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // Inflate the layout containing a title and body text.
        ViewGroup rootView = (ViewGroup) inflater
                .inflate(R.layout.fragment_screen_slide_page, container, false);

        // Set the title view to show the page number.
        ((TextView) rootView.findViewById(android.R.id.text1)).setText(
                getString(R.string.title_template_step, mPageNumber + 1));
        displayImageFile(rootView);
        return rootView;
    }

    private void displayImageFile (ViewGroup view) {

        ImageView imageView = (ImageView) view.findViewById(R.id.item_image_to_display);

        mImageLoader.displayImage(mImages[mPageNumber], imageView, mOptions);

    }

    /**
     * Returns the page number represented by this fragment object.
     */
    public int getPageNumber() {
        return mPageNumber;
    }
}

Layout activity_screen_slide.xml used by ScreenSlideActivity and id for ViewPager:

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

fragment_screen_slide_page.xml used by ScreenSlidePageFragment:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <!-- Dummy content. -->

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="16dp" >

        <TextView
            android:id="@android:id/text1"
            style="?android:textAppearanceLarge"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="16dp"
            android:textStyle="bold" />

        <TextView
            style="?android:textAppearanceMedium"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:lineSpacingMultiplier="1.2"
            android:text="@string/lorem_ipsum" />

        <TextView
            android:id="@+id/item_details"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:gravity="center_vertical"
            android:text="@string/item_details" />

        <TextView
            android:id="@+id/item_type_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="@string/item_type_text" />

        <Spinner
            android:id="@+id/item_type"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:prompt="@string/item_type_text"
            android:text="@string/item_type" />

        <TextView
            android:id="@+id/item_name_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="@string/item_name_text" />

        <EditText
            android:id="@+id/item_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:gravity="top|left"
            android:hint="@string/item_name"
            android:inputType="text" />

        <TextView
            android:id="@+id/item_text_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="@string/item_text_text" />

        <EditText
            android:id="@+id/item_text"
            android:layout_width="wrap_content"
            android:layout_height="100dp"
            android:layout_marginLeft="10dp"
            android:ems="10"
            android:gravity="top|left"
            android:hint="@string/item_text"
            android:inputType="textMultiLine" />

        <TextView
            android:id="@+id/sound_edit_text"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:gravity="center_vertical"
            android:text="@string/sound_edit" />

        <ImageView
            android:id="@+id/item_add_audio"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:contentDescription="@string/cd_image_add_button"
            android:src="@android:drawable/ic_menu_add" />

        <TextView
            android:id="@+id/recording_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginBottom="20dp"
            android:layout_marginTop="20dp"
            android:text="@string/recording_text" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:padding="16dp" >

            <ImageButton
                android:id="@+id/item_play_audio"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="33"
                android:contentDescription="@string/cd_play_sound_button"
                android:soundEffectsEnabled="false"
                android:src="@drawable/play" />

            <ImageButton
                android:id="@+id/item_stop_audio"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="34"
                android:contentDescription="@string/cd_stop_sound_button"
                android:soundEffectsEnabled="false"
                android:src="@drawable/stop" />

            <ImageButton
                android:id="@+id/item_record_audio"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="33"
                android:contentDescription="@string/cd_record_sound_button"
                android:soundEffectsEnabled="false"
                android:src="@drawable/rec" />
        </LinearLayout>

        <TextView
            android:id="@+id/edit_image"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:gravity="center_vertical"
            android:text="@string/edit_image" />

        <TextView
            android:id="@+id/image_replace_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginBottom="10dp"
            android:layout_marginTop="10dp"
            android:text="@string/image_replace"
            android:visibility="visible" />

        <ImageView
            android:id="@+id/item_image_to_display"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:adjustViewBounds="true"
            android:contentDescription="@string/cd_item_image" />

        <TextView
            android:id="@+id/item_image_effect_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="@string/item_image_effect_text" />

        <Spinner
            android:id="@+id/item_image_effect"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp" />

        <TextView
            android:id="@+id/item_text_color_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="@string/item_text_color_text" />

        <Spinner
            android:id="@+id/item_text_color"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp" />

        <TextView
            android:id="@+id/item_text_size_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="@string/item_text_size_text" />

        <EditText
            android:id="@+id/item_text_size"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:hint="@string/item_text_size"
            android:inputType="number" />

        <TextView
            android:id="@+id/item_text_style_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="@string/item_text_style_text" />

        <Spinner
            android:id="@+id/item_text_style"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp" />

        <TextView
            android:id="@+id/item_text_alignment_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="@string/item_text_alignment_text" />

        <Spinner
            android:id="@+id/item_text_alignment"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp" />

        <TextView
            android:id="@+id/item_background_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="@string/item_background_text" />

        <Spinner
            android:id="@+id/item_background"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp" />
    </LinearLayout>

</ScrollView>

Also, here's the OOM error that I run into:

05-06 16:37:59.656: E/ImageLoader(3175): null
05-06 16:37:59.656: E/ImageLoader(3175): java.lang.OutOfMemoryError
05-06 16:37:59.656: E/ImageLoader(3175):    at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
05-06 16:37:59.656: E/ImageLoader(3175):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:529)
05-06 16:37:59.656: E/ImageLoader(3175):    at com.nostra13.universalimageloader.core.ImageDecoder.decode(ImageDecoder.java:82)
05-06 16:37:59.656: E/ImageLoader(3175):    at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.decodeImage(LoadAndDisplayImageTask.java:270)
05-06 16:37:59.656: E/ImageLoader(3175):    at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.tryLoadBitmap(LoadAndDisplayImageTask.java:224)
05-06 16:37:59.656: E/ImageLoader(3175):    at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.run(LoadAndDisplayImageTask.java:149)
05-06 16:37:59.656: E/ImageLoader(3175):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
05-06 16:37:59.656: E/ImageLoader(3175):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
05-06 16:37:59.656: E/ImageLoader(3175):    at java.lang.Thread.run(Thread.java:856)

What can I look at/change in order to get rid of the OOM errors?

هل كانت مفيدة؟

المحلول

Turns out it was unbindDrawables that ended up fixing my problem. Not sure what I was doing wrong with it before (up too late...??? ;-)), but I ran across this post and it solved my problem. The aforementioned post was a little different than some of the other unbindDrawable posts I had seen and I didn't get any java.lang.UnsupportedOperationException: removeAllViews() is not supported in AdapterView errors like I had when I had tried some other versions (which could have just been something stupid on my part).

I implemented the following in the ScreenSildePageFragment class and it solved my OOM issues:

@Override
protected void onDestroy()
{
        super.onDestroy();

        unbindDrawables(mRootView.findViewById(R.id.content)); // <---This should be the ID of this fragments (ScreenSlidePageFragment) layout
}

private void unbindDrawables(View view)
{
        if (view.getBackground() != null)
        {
                view.getBackground().setCallback(null);
        }
        if (view instanceof ViewGroup && !(view instanceof AdapterView))
        {
                for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++)
                {
                        unbindDrawables(((ViewGroup) view).getChildAt(i));
                }
                ((ViewGroup) view).removeAllViews();
        }
}

Note: I didn't use System.gc(); after calling unbindDrawables() in onDestroy() as mentioned in the post. Using it didn't seem to make any real difference on the devices I tested on and I figured it was probably better to just let the system manage garbage collection.

نصائح أخرى

I ran into a similar problem. Instantiating the adapter with getChildFragmentManager() instead of getFragmentManager() fixed my issue.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top