Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

android viewpager out of memory

first i would like to say that english is not my native language. So please forgive me my mistakes.

To my problem: I have a ViewPager with 10 pages and tabs. The first window is for setting and the others are questions.

You start with the first question and i show an image, if you click "yes" "no" then you go to the next page where the second picture is shown with another question.

I get everytime the oom error (as i get to the 7 page). I read some tipps about it i now i use bitmap decoder everytime i bind the image to my ImageView. But that dont help much. I still have the same problem. My decoder has *.inPurgeable = true;

I know there is an option to change your manifest.xml to allow more heap size but i think that will only delay the error. Can someone look through my code please and tell me something that i am doing wrong. Cause it seems to me fine but cause i am new to programming i could have made some big mistakes :)

My viewpager with the adapter:

public class WaldViewPager extends FragmentActivity implements ActionBar.TabListener {

    private static AppSectionsPagerAdapter mAppSectionsPagerAdapter;
    static private ViewPager mViewPager;
    private static Context context;
    public static int bitmap;
    private int width, height;
    private ViewGroup rootWald;
    private static int textSize = 0;
    private Dialog dialog;
    public static int lastUsed = 1;
    private static int ergebnis = 0;
    private static int[] fragenListe = new int[8];
    private static int[] antworten = new int[9];

    public static void setErgebnis(int zahl){
        ergebnis = zahl;
    }

    public static int getErgebnis(){
        return ergebnis;
    }

    public static void setAntwort(int position, int antwort){
        antworten[position-1] = antwort;
    }

    public static int getAntwort(int position){
        return antworten[position-1];
    }

    public static void setPage(int position){
        mViewPager.setCurrentItem(position, true);
    }

    public static int getPage(){
        return mViewPager.getCurrentItem();
    }

    private void resetListe(){
        for(int i=0; i<fragenListe.length; i++){
            fragenListe[i]=0;
        }
    }

    private void resetAntworten(){
        for(int i=0; i<antworten.length; i++){
            antworten[i]=0;
        }
    }

    public static boolean getFrage(int position){
        if(fragenListe[position-2] == 1){
            return true;
        }else{
            return false;
        }
    }

    public static void setPageVisible(int position, boolean status){
        if(status == true){
            fragenListe[position-2] = 1;
        }else if(status == false){
            fragenListe[position-2] = 0;
        }
    }

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_viewpager);
        overridePendingTransition(R.anim.fade_out, R.anim.fade_in);
        mAppSectionsPagerAdapter = new AppSectionsPagerAdapter(getSupportFragmentManager());
        WaldViewPager.context = getApplicationContext();
        berechneSchriftgroese();
        setupHelpInfoDialog();
        resetListe();
        resetAntworten();

        rootWald = (ViewGroup) findViewById(R.id.toast_layout_root);

        final ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        actionBar.setLogo(R.drawable.fake);

        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mAppSectionsPagerAdapter);
        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {

            @Override
            public void onPageSelected(int position){
                actionBar.getTabAt(position).select();
                ViewParent root = findViewById(android.R.id.content).getParent();
                findAndUpdateSpinner(root, position);
            }

            private boolean findAndUpdateSpinner(Object root, int position){
               if (root instanceof android.widget.Spinner){
                   Spinner spinner = (Spinner) root;
                   spinner.setSelection(position);
                   return true;
               }else if (root instanceof ViewGroup){
                   ViewGroup group = (ViewGroup) root;
                   if (group.getId() != android.R.id.content){
                       for (int i = 0; i < group.getChildCount(); i++){
                           if (findAndUpdateSpinner(group.getChildAt(i), position)){
                               return true;
                           }
                       }
                   }
               }
               return false;
           }
        });

        for (int i = 0; i < mAppSectionsPagerAdapter.getCount(); i++) {
            actionBar.addTab(actionBar.newTab().setText(mAppSectionsPagerAdapter.getPageTitle(i)).setTabListener(this));
        }

        mViewPager.setCurrentItem(1, true);
    }

    @Override
    public void onBackPressed() {
        if (mViewPager.getCurrentItem() == 1) {
            super.onBackPressed();
        } else {
            mViewPager.setCurrentItem(1, true);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater menuInflater = getMenuInflater();
        menuInflater.inflate(R.menu.bottom_bar_frage, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_settings_frage:
                if(mViewPager.getCurrentItem()==0){
                    mViewPager.setCurrentItem(lastUsed, true);
                }else{
                    lastUsed = mViewPager.getCurrentItem();
                    mViewPager.setCurrentItem(0, true);
                }
                return true;
            case R.id.menu_info:
                dialog.show();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    private void setupHelpInfoDialog(){
        dialog = new Dialog(WaldViewPager.this);
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        dialog.setCancelable(true);
        dialog.setContentView(R.layout.dialog_info);
        dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
        TextView text = (TextView) dialog.findViewById(R.id.dialog_ueberschrift);
        text.setText("Bedienung der App");
        if(MainViewPager.getTextSize()!=0){
            text.setTextSize(text.getTextSize()-MainViewPager.getTextSize());
        }
        text = (TextView) dialog.findViewById(R.id.dialog_text1);
        text.setText("-Wischfunktion:");
        if(MainViewPager.getTextSize()!=0){
            text.setTextSize(text.getTextSize()-MainViewPager.getTextSize());
        }
        text = (TextView) dialog.findViewById(R.id.dialog_text1_sub);
        text.setText("Zum Navigieren können Sie entweder auf die Tabs zurückgreifen oder Sie wischen das Fenster links oder rechts");
        if(MainViewPager.getTextSize()!=0){
            text.setTextSize(text.getTextSize()-MainViewPager.getTextSize());
        }
        text = (TextView) dialog.findViewById(R.id.dialog_text2);
        text.setText("-Zoomfunktion:");
        if(MainViewPager.getTextSize()!=0){
            text.setTextSize(text.getTextSize()-MainViewPager.getTextSize());
        }
        text = (TextView) dialog.findViewById(R.id.dialog_text2_sub);
        text.setText("Wenn Sie auf das Bild klicken, können Sie es mit 2 Fingern vergrößern bzw. verkleinern");
        if(MainViewPager.getTextSize()!=0){
            text.setTextSize(text.getTextSize()-MainViewPager.getTextSize());
        }
        text = (TextView) dialog.findViewById(R.id.dialog_text3);
        text.setText("-Erklärungshilfe:");
        if(MainViewPager.getTextSize()!=0){
            text.setTextSize(text.getTextSize()-MainViewPager.getTextSize());
        }
        text = (TextView) dialog.findViewById(R.id.dialog_text3_sub);
        text.setMovementMethod(LinkMovementMethod.getInstance());
        text.setText(ClickableText.addClickablePart("Damit Sie wenig Zeit beim Suchen der Fremd/Fachwörtern verlieren, können Sie Wörter wie \u200EClypeus\u200E direkt hier nachschlagen", context, rootWald), BufferType.SPANNABLE);
        if(MainViewPager.getTextSize()!=0){
            text.setTextSize(text.getTextSize()-MainViewPager.getTextSize());
        }
        ImageView bild = (ImageView) dialog.findViewById(R.id.dialog_bild1);
        ImageView bild = (ImageView) dialog.findViewById(R.id.dialog_bild1);
        bild.setImageBitmap(DecodeImage.decode(bild.getContext().getResources(), R.drawable.swipe));
        bild = (ImageView) dialog.findViewById(R.id.dialog_bild2);
        bild.setImageBitmap(DecodeImage.decode(bild.getContext().getResources(),
R.drawable.swipe_bild));
    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        // TODO Auto-generated method stub
        mViewPager.setCurrentItem(tab.getPosition(), true);
    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        // TODO Auto-generated method stub  
    }

    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) {
        // TODO Auto-generated method stub  
    }

AppSectionsPagerAdapter

    public static class AppSectionsPagerAdapter extends FragmentStatePagerAdapter {

        public AppSectionsPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Parcelable saveState() {
            return null;
        }

        @Override
        public Fragment getItem(int i) {        
            switch (i) {
            case 0:
                return new SettingsFrage();
            case 1:
                return new FrageA();
            case 2:
                return new FrageB();
            case 3:
                return new FrageC();
            case 4:
                return new FrageD();
            case 5:
                return new FrageE();
            case 6:
                return new FrageF();
            case 7:
                return new FrageG();
            case 8:
                return new FrageH();
            case 9:
                return new FrageI();
            }
            return null;
        }

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

        @Override
        public float getPageWidth(int position) {
            if(position == 0){
                return super.getPageWidth(position)*0.6f;
            }
            return super.getPageWidth(position);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            switch(position){
            case 0:
                return "Settings";
            case 1:
                return "Einkerbung";
            case 2:
                return "Einbuchtung";
            case 3:
                return "Farbe";
            case 4:
                return "Stirndreieck";
            case 5:
                return "Haare";
            case 6:
                return "Beborstung";
            case 7:
                return "Hinterhaupt";
            case 8:
                return "Pigmentierung";
            case 9:
                return "Mesosoma";
            }
            return null;
        }
    }

    public static Context getContext(){
        return WaldViewPager.context;
    }

    public static int getTextSize(){
        return textSize;
    }

    private void berechneSchriftgroese(){
        Display display = getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        width = size.x;
        height = size.y;
        if(width<=480 || height<=480){
            textSize = 12;
        }
    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        overridePendingTransition(R.anim.fade_out, R.anim.fade_in);
    }
}

One of my question:

public class FrageB extends Fragment implements OnClickListener{

    public static ImageView bild;
    public static TextView ueberschrift, frage, frageZusatz1, frageZusatz2;
    public static View viewA, viewB, viewC;
    public static RadioButton auswahlA, auswahlB, auswahlC;

    String stringUeberschrift = "Einbuchtung";
    String stringFrage = "Welche Form hat der Hinterrand des Kopfes?";
    String stringAuswahlA = "keine Delle";
    String stringAuswahlB = "Delle";
    String stringAuswahlC = "unsicher";
    String stringFrageZusatz1 = "keine Delle: nicht oder nur schwach eingebuchtet, keine deutliche Delle";
    String stringFrageZusatz2 = "Delle: tief eingebuchtet, deutliche Delle";

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fake_frage, container, false);
        ViewGroup root = (ViewGroup) v.findViewById(R.id.toast_layout_root);

        bild = (ImageView) v.findViewById(R.id.frage_bild);
        frage = (TextView) v.findViewById(R.id.frage_frage);
        ueberschrift = (TextView) v.findViewById(R.id.frage_ueberschrift);
        auswahlA = (RadioButton) v.findViewById(R.id.frage_auswahl1);
        auswahlB = (RadioButton) v.findViewById(R.id.frage_auswahl2);
        auswahlC = (RadioButton) v.findViewById(R.id.frage_auswahl3);
        frageZusatz1 = (TextView) v.findViewById(R.id.frage_zusatz1);
        frageZusatz2 = (TextView) v.findViewById(R.id.frage_zusatz2);
        viewA = (View) v.findViewById(R.id.fake_view1);
        viewB = (View) v.findViewById(R.id.fake_view2);
        viewC = (View) v.findViewById(R.id.fake_view3);

        auswahlC.setEnabled(false);
        bild.setOnClickListener(this);
        auswahlA.setOnClickListener(this);
        auswahlB.setOnClickListener(this);
        auswahlC.setOnClickListener(this);
        auswahlA.setEnabled(false);
        auswahlB.setEnabled(false);
        bild.setClickable(false);

        if(WaldViewPager.getFrage(2)){
            ZeigeFrage.unhide(2);
        }

        ueberschrift.setMovementMethod(LinkMovementMethod.getInstance());
        frage.setMovementMethod(LinkMovementMethod.getInstance());
        frageZusatz1.setMovementMethod(LinkMovementMethod.getInstance());
        frageZusatz2.setMovementMethod(LinkMovementMethod.getInstance());

        frageZusatz1.setText(ClickableText.addClickablePart(stringFrageZusatz1, WaldViewPager.getContext(), root), BufferType.SPANNABLE);
        frageZusatz2.setText(ClickableText.addClickablePart(stringFrageZusatz2, WaldViewPager.getContext(), root), BufferType.SPANNABLE);       
        auswahlA.setText(stringAuswahlA);
        auswahlB.setText(stringAuswahlB);
        auswahlC.setText(stringAuswahlC);   
        ueberschrift.setText(ClickableText.addClickablePart(stringUeberschrift, WaldViewPager.getContext(), root), BufferType.SPANNABLE);
        frage.setText(ClickableText.addClickablePart(stringFrage, WaldViewPager.getContext(), root), BufferType.SPANNABLE);

        if(WaldViewPager.getTextSize()!=0){
            auswahlA.setTextSize(auswahlA.getTextSize()-WaldViewPager.getTextSize());
            auswahlB.setTextSize(auswahlB.getTextSize()-WaldViewPager.getTextSize());
            auswahlC.setTextSize(auswahlC.getTextSize()-WaldViewPager.getTextSize());
            ueberschrift.setTextSize(ueberschrift.getTextSize()-WaldViewPager.getTextSize());
            frage.setTextSize(frage.getTextSize()-WaldViewPager.getTextSize());
            frageZusatz1.setTextSize(frageZusatz1.getTextSize()-WaldViewPager.getTextSize());
            frageZusatz2.setTextSize(frageZusatz2.getTextSize()-WaldViewPager.getTextSize());
        }

        return v;
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

        if (isVisibleToUser) { 
            if(WaldViewPager.getFrage(2)){
                ZeigeFrage.unhide(2);
            }
        }
    }

    @Override
    public void onClick(View v) {
        if(v == bild){
            Intent intent = new Intent(WaldViewPager.getContext(), ShowImage.class);
            WaldViewPager.bitmap = R.drawable.frage2;
            startActivity(intent);
        }
        if(v == auswahlA){
            WaldViewPager.setAntwort(WaldViewPager.getPage(), 1);
            WaldViewPager.setPageVisible(3, true);
            WaldViewPager.setErgebnis(0);
            WaldViewPager.setPage(3);
        }
        if(v == auswahlB){
            //coptoformica
            WaldViewPager.setAntwort(WaldViewPager.getPage(), 2);
            WaldViewPager.setErgebnis(2);
            Intent intent = new Intent(WaldViewPager.getContext(), ErgebnisB.class);
            startActivity(intent);
        }
        if(v == auswahlC){

        }
    }
}

My decodeImage

public class DecodeImage {

    public static Bitmap decode(Resources res, int resId){
        BitmapFactory.Options bfOptions=new BitmapFactory.Options();
        bfOptions.inDither = false;
        bfOptions.inPurgeable = true;               
        bfOptions.inInputShareable = true;
        bfOptions.inTempStorage = new byte[32 * 1024]; 
        return BitmapFactory.decodeResource(res, resId, bfOptions);
    }
}

I would appreciate any help. feel free to ask for over peaces of code. this app works fine on some devices but on other not. has to be something with heap size change i guess.

EDIT: found the solution. the answer with the bitmap.recycle() works but due to my art of code i was lazy to change a lot and i used something else.

as for ViewPager android provides you with

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
}

i upgraded the line

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) { 
        //if you can see the fragment
    }else{
        //if you dont
    }
}

to

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) { 
        //if you can see the fragment
    }else{
        //if you dont
        imageViewToDelete.setImageDrawable(null); //this is ImageView from Fragment
    }
}

REMEMBER: setUserVisibleHint() is set earlier than the onCreateView()

good luck

like image 886
vandyke Avatar asked Aug 09 '13 09:08

vandyke


4 Answers

For each imageView you will have to call recycle() method. So, before the line:

bild.setImageBitmap(DecodeImage.decode(bild.getContext().getResources(), R.drawable.swipe_bild));

You have to put the line:

((BitmapDrawable) bild.getDrawable()).getBitmap().recycle();

If the problem persists, it's because the image is too large and then you will have to compress it

like image 60
Renan Bandeira Avatar answered Nov 10 '22 18:11

Renan Bandeira


I faced same problem and solved it, as follows

Best example is given in android developer guide, follow this guide step by step.

1.implement inJustDecodeBounds http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

2.Follow the below guide for asynchronous and caching, you can also download the sample from same link. http://developer.android.com/training/displaying-bitmaps/display-bitmap.html

like image 26
arun-r Avatar answered Nov 10 '22 18:11

arun-r


I had OutOfMemory error in ViewPager with images (720*1200). Combining advices I found the solution, which worked for me:

  • put images into drawable-nodpi category (remove from all other drawable categories)

  • decoding drawable into bitmap with options (inSampleSize = 1, ARGB_8888)

like image 1
Vakcina Avatar answered Nov 10 '22 16:11

Vakcina


I was using Picasso and had this problem too... Just erase the dummy content you placed into the ImageView. Erase the src tag, as you won't need it with Picasso.

<ImageView
        android:id="@+id/img"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:scaleType="centerCrop"
        **android:src="@drawable/myDrawable"**/>

This happens because the drawables have to be loaded even if you replace them by Picasso afterward, and after you load many images into your ViewPager, it causes the OutOfMemory.

like image 1
dianakarenms Avatar answered Nov 10 '22 17:11

dianakarenms