FragmentStatePagerAdapter OutOfMemoryError

I run OutOfMemoryErrors in the application I'm working on, and it's hard for me to figure out how to fix it and what the problem is. I am using the FragmentStatePagerAdapter as this seems like the best / recommended alternative. I also use Universal Image Loader v.1.8.4 . It happens that when you look at views, the heap grows and eventually ends up in memory. Here is a small conclusion:

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 of all, yes, I did a lot to dig at stackoverflow and other sites, trying to figure out what the problem is. I tried various solutions that process bitmaps, use unbindDrawables and try to remove views / process bitmaps in destroyItem () PagerAdapter ... to name a few. None of them worked for me (I can provide more detailed information about what I did, if necessary).

So, in a nutshell, I can reproduce my problem using a modified version of this example (from the Google Developers site). I changed it a bit to work with Universal Image Loader v.1.8.4 , and also made the layout a bit more complex to mimic somewhat what I have in the application I'm working on. The reason I changed the layout was because everything works fine if you make the layout very simple and include only the image and some text fields. When the layout becomes more complex, and when you start adding additional pages to the adapter, you start working with OOM errors. However, I'm not sure if this is a problem with the layout or UIL ... read on ...

I ran MAT in Eclipse, and here is what it says under a single Leak Suspects post (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 view the Dominators Tree and expand ScreenSlidePagerAdapter, it will display 25 of 59 entries for the following:

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

I am not an expert in this tool, and I'm pretty new to Android and development in general, but it seems that the saved state for the adapter is not cleared correctly and that causes the OOM problem (it saves the whole view, not just bitmap images). However, I could not figure out how to clear / release / destroy / regardless of the stored state data or if I am doing something wrong elsewhere. I came across one message that tried to use .setSaveEnabled(false) , but that didn't make any difference, I still had OOM errors. I even tried overriding saveState () for the adapter and returning null, and that didn't matter either.

Here is the relevant code / configuration information which hopefully answers most of the questions:

For UIL, I just use the default configuration, since the changes do not seem to change:

 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 caused by the 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 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; } } 

The 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 is the OOM error that I am encountering:

 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 see / change to get rid of OOM errors?

+4
source share
2 answers

Turns out it was unbindDrawables, which eventually fixed my problem. Not sure what I was doing wrong with it (too late ... ??? ;-)), but I ran into this post and solved my problem, The above post was slightly different from some other unbindDrawable posts I saw, and I didn't get java.lang.UnsupportedOperationException: removeAllViews() is not supported in AdapterView errors java.lang.UnsupportedOperationException: removeAllViews() is not supported in AdapterView like me when I tried some other versions (which might just be silly of me).

I implemented the following in the ScreenSildePageFragment class and solved my problems with OOM:

 @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 did not use System.gc(); after calling unbindDrawables () in onDestroy () as indicated in the post. Using this did not show any real difference on the tested devices, and I thought it was probably better to just let the system control the garbage collection.

+4
source

I had a similar problem. Activating the adapter using getChildFragmentManager() instead of getFragmentManager() fixed my problem.

0
source

Source: https://habr.com/ru/post/1479452/


All Articles