I have a ViewPager in my app that contains 8 fragments, some of which contain more than 10 images, displayed in a linear layout in a column. Sometimes when swapping between the fragments the app crashes because of a java.lang.OutOfMemoryError
I have no idea how to avoid this error I think that it happens because the ViewPager and the big amount of images requires high amount of memory.
Do you have any idea on how to solve this problem?
P.S I Minimized the images quality to as low as possible.
In MainActivity onCreate method:
ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
setupViewPager(viewPager);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
if (tabLayout != null) {
tabLayout.setupWithViewPager(viewPager);
}
setupViewPager():
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new S1(), getString(R.string.stage1));
adapter.addFragment(new S2(), getString(R.string.stage2));
adapter.addFragment(new S3(), getString(R.string.stage3));
adapter.addFragment(new S4(), getString(R.string.stage4));
adapter.addFragment(new S5(), getString(R.string.stage5));
adapter.addFragment(new S6(), getString(R.string.stage6));
adapter.addFragment(new S7(), getString(R.string.stage7));
adapter.addFragment(new S8(), getString(R.string.stage8));
viewPager.setAdapter(adapter);
}
class ViewPagerAdapter:
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
@Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
Fragemt S1:
public class S1 extends Fragment {
public S1() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_s1, container, false);
ImageView image1 = (ImageView)rootView.findViewById(R.id.imageView_S0P1);
ImageView image2 = (ImageView)rootView.findViewById(R.id.imageView_S0P2);
ImageView image3 = (ImageView)rootView.findViewById(R.id.imageView_S0P3);
ImageView image4 = (ImageView)rootView.findViewById(R.id.imageView_S0P4);
ImageView image5 = (ImageView)rootView.findViewById(R.id.imageView_S0P5);
ImageView image6 = (ImageView)rootView.findViewById(R.id.imageView_S0P6);
ImageView image7 = (ImageView)rootView.findViewById(R.id.imageView_S0P7);
ImageView image8 = (ImageView)rootView.findViewById(R.id.imageView_S0P8);
ImageView image9 = (ImageView)rootView.findViewById(R.id.imageView_S0P9);
ImageView image10 = (ImageView)rootView.findViewById(R.id.imageView_S0P10);
image1.setImageResource(R.drawable.s0p1);
image2.setImageResource(R.drawable.s0p2);
image3.setImageResource(R.drawable.s0p3);
image4.setImageResource(R.drawable.s0p4);
image5.setImageResource(R.drawable.s0p5);
image6.setImageResource(R.drawable.s0p6);
image7.setImageResource(R.drawable.s0p7);
image8.setImageResource(R.drawable.s0p8);
image9.setImageResource(R.drawable.s0p9);
image10.setImageResource(R.drawable.s0p10);
return rootView;
}
}
fragment_s1.xml:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/scrollView_intro"
tools:context="appinventor.ai_itiel_maimon.Rubiks_cube.s1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
//TextView
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:id="@+id/imageView_S0P1"
android:scaleType="fitCenter"
android:contentDescription="@string/image_description" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:id="@+id/imageView_S0P2"
android:scaleType="fitCenter"
android:contentDescription="@string/image_description" />
//TextView
//TextView
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:id="@+id/imageView_S0P3"
android:scaleType="fitCenter"
android:contentDescription="@string/image_description" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:id="@+id/imageView_S0P4"
android:scaleType="fitCenter"
android:contentDescription="@string/image_description" />
//TextView
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:id="@+id/imageView_S0P5"
android:scaleType="fitCenter"
android:contentDescription="@string/image_description" />
//TextView
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:id="@+id/imageView_S0P6"
android:scaleType="fitCenter"
android:contentDescription="@string/image_description" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:id="@+id/imageView_S0P7"
android:scaleType="fitCenter"
android:contentDescription="@string/image_description" />
//TextView
//TextView
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:id="@+id/imageView_S0P8"
android:scaleType="fitCenter"
android:contentDescription="@string/image_description" />
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:id="@+id/imageView_S0P9"
android:scaleType="fitCenter"
android:contentDescription="@string/image_description" />
//TextView
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:id="@+id/imageView_S0P10"
android:scaleType="fitCenter"
android:contentDescription="@string/image_description" />
</LinearLayout>
</ScrollView>
Logcat:
07-17 20:58:31.334 30652-30652/appinventor.ai_itiel_maimon.Rubiks_cube E/AndroidRuntime: FATAL EXCEPTION: main
Process: appinventor.ai_itiel_maimon.Rubiks_cube, PID: 30652
java.lang.OutOfMemoryError: Failed to allocate a 8876812 byte allocation with 7873968 free bytes and 7MB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:856)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:675)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:2228)
at android.content.res.Resources.loadDrawableForCookie(Resources.java:4211)
at android.content.res.Resources.loadDrawable(Resources.java:4085)
at android.content.res.Resources.getDrawable(Resources.java:2005)
at android.content.res.Resources.getDrawable(Resources.java:1987)
at android.support.v7.widget.ResourcesWrapper.getDrawable(ResourcesWrapper.java:133)
at android.content.Context.getDrawable(Context.java:464)
at android.support.v4.content.ContextCompatApi21.getDrawable(ContextCompatApi21.java:26)
at android.support.v4.content.ContextCompat.getDrawable(ContextCompat.java:352)
at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:193)
at android.support.v7.widget.AppCompatDrawableManager.getDrawable(AppCompatDrawableManager.java:181)
at android.support.v7.widget.AppCompatImageHelper.setImageResource(AppCompatImageHelper.java:72)
at android.support.v7.widget.AppCompatImageView.setImageResource(AppCompatImageView.java:71)
at appinventor.ai_itiel_maimon.Rubiks_cube.S7.onCreateView(S7.java:28)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:2074)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
at android.support.v4.app.FragmentManagerImpl.attachFragment(FragmentManager.java:1464)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:748)
at android.support.v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:1632)
at android.support.v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:637)
at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:143)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1235)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:666)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:628)
at android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:609)
at android.support.design.widget.TabLayout$ViewPagerOnTabSelectedListener.onTabSelected(TabLayout.java:2168)
at android.support.design.widget.TabLayout.dispatchTabSelected(TabLayout.java:1157)
at android.support.design.widget.TabLayout.selectTab(TabLayout.java:1151)
at android.support.design.widget.TabLayout.selectTab(TabLayout.java:1124)
at android.support.design.widget.TabLayout$Tab.select(TabLayout.java:1419)
at android.support.design.widget.TabLayout$TabView.performClick(TabLayout.java:1524)
at android.view.View$PerformClick.run(View.java:22526)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7229)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
EDIT:
I used bitmaps to load the images and it gave me java.lang.OutOfMemoryError: Failed to allocate a 8876812 byte allocation with 7889984 free bytes and 7MB until OOM
This is the code I used:
Fragment S1:
public class Intro extends S1 {
public S1 () {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_s1, container, false);
final int IMAGE_WIDTH = 500;
final int IMAGE_HEIGHT = 500;
ImageView image1 = (ImageView)rootView.findViewById(R.id.imageView_S0P1);
ImageView image2 = (ImageView)rootView.findViewById(R.id.imageView_S0P2);
ImageView image3 = (ImageView)rootView.findViewById(R.id.imageView_S0P3);
ImageView image4 = (ImageView)rootView.findViewById(R.id.imageView_S0P4);
ImageView image5 = (ImageView)rootView.findViewById(R.id.imageView_S0P5);
ImageView image6 = (ImageView)rootView.findViewById(R.id.imageView_S0P6);
ImageView image7 = (ImageView)rootView.findViewById(R.id.imageView_S0P7);
ImageView image8 = (ImageView)rootView.findViewById(R.id.imageView_S0P8);
ImageView image9 = (ImageView)rootView.findViewById(R.id.imageView_S0P9);
ImageView image10 = (ImageView)rootView.findViewById(R.id.imageView_S0P10);
image1.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.drawable.s0p1, IMAGE_WIDTH, IMAGE_HEIGHT));
image2.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.drawable.s0p2, IMAGE_WIDTH, IMAGE_HEIGHT));
image3.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.drawable.s0p3, IMAGE_WIDTH, IMAGE_HEIGHT));
image4.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.drawable.s0p4, IMAGE_WIDTH, IMAGE_HEIGHT));
image5.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.drawable.s0p5, IMAGE_WIDTH, IMAGE_HEIGHT));
image6.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.drawable.s0p6, IMAGE_WIDTH, IMAGE_HEIGHT));
image7.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.drawable.s0p7, IMAGE_WIDTH, IMAGE_HEIGHT));
image8.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.drawable.s0p8, IMAGE_WIDTH, IMAGE_HEIGHT));
image9.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.drawable.s0p9, IMAGE_WIDTH, IMAGE_HEIGHT));
image10.setImageBitmap(
decodeSampledBitmapFromResource(getResources(), R.drawable.s0p10, IMAGE_WIDTH, IMAGE_HEIGHT));
// Inflate the layout for this fragment
return rootView;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
}
I solved this problem by using the Fresco library to load the images. It's very helpful! http://frescolib.org