11

i am showing 150+ images in viewpager, when page size crossed 70 app is crashing , all images are loading from network , and i have fallowed [link]: Strange out of memory issue while loading an image to a Bitmap object

and i am recycling it whenever page swiping reaches 4,

for 70 page app taking 200 MB of memory.

i need help from you, how to handle it

i have to show all pages with swiping...

i have also used Runtime.getRuntime().gc();

is any way to releasing memory if app memory is reaches the 50+ MB

thanks in advance

Community
  • 1
  • 1
Sheetal Suryan
  • 495
  • 2
  • 7
  • 19

6 Answers6

18

The complete solution can be found below, the important lines are those in the destroyItem method:

private class ContentPagerAdapter extends PagerAdapter {
    @Override
    public void destroyItem(View collection, int position, Object o) {
        View view = (View)o;
        ((ViewPager) collection).removeView(view);
        view = null;
    }

    @Override
    public void finishUpdate(View arg0) {
        // TODO Auto-generated method stub

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

    @Override
    public Object instantiateItem(View context, int position) {
        ImageView imageView = new ImageView(getApplicationContext());
        imageView.findViewById(R.id.item_image);
        imageView.setImageBitmap(BitmapFactory.decodeResource(getResources(), ids[position]));

        ((ViewPager) context).addView(imageView);

        return imageView;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view==((ImageView)object);
    }

    @Override
    public void restoreState(Parcelable arg0, ClassLoader arg1) {
        // TODO Auto-generated method stub
    }
    @Override
    public Parcelable saveState() {
        // TODO Auto-generated method stub
        return null;
    }
    @Override
    public void startUpdate(View arg0) {
        // TODO Auto-generated method stub

    }
Mark
  • 541
  • 2
  • 12
4

I think this happens because you have a memory leak, double check your variables, don't use static vars for anything big, use final when possible, make all members private.

i suggest you make a commit (or save your current code) and then try to do what i asked and see if it fixes it.

a code sample would let me tell you if you have memory leaks, maybe you can post the code somewhere like on github or google code

Bottom line: you could be doing everything right but a variable still holds a reference to your images so the garbage collector can't touch them.

I know saying you have a memory leak hurts but please don't be alarmed this happens to the best of the best, because it's so easy to happen.

NOTE: No matter how big the data i load from network apps never needed more than the size of 1 file if handled correctly.

Thanks

Shereef Marzouk
  • 3,282
  • 7
  • 41
  • 64
1

Sheetal,

Having looked at your code can you try the following:

@Override
public void destroyItem(View collection, int position, Object o) {
    Log.d("DESTROY", "destroying view at position " + position);
    View view = (View) o;
    ((ViewPager) collection).removeView(view);
    view = null;
}

This should release the imageView for garbage collection.

Mark
  • 541
  • 2
  • 12
0

Are you loading your images in the onCreateView() view method?

The framework seems to takes care of the memory management requirements when doing it this way. I had tried loading my images in my FragmentPageAdapter passing them into my Fragment constructor preloaded or as part of the Fragment instaniateItem method but these both gave me the issue that you are facing. In the end I passed the information needed to load each image into the Fragment constructor and then used these details in the onCreateView() method.

Mark

Mark
  • 541
  • 2
  • 12
  • no,i am not loading images in the onCreateView() view method. all images are loading in instantiateItem PagerAdapter – Sheetal Suryan Feb 21 '12 at 10:48
  • is any way to free (release) app memory? which images are using – Sheetal Suryan Feb 21 '12 at 10:56
  • I think the way your app is structured currently will hold a reference to all the images, so you will run out of memory at some point anyway, especially on smaller devices. You need to move the creation of your images to the onCreateView method, this way the framework will only hold onto three image references, i.e. the previous image, the currently displayed image and the next image in the sequence. These images are swapped out on the next swipe, with one of the images falling off the list of three and another being added in its place. – Mark Feb 21 '12 at 11:10
  • thanks Mark, can you give any sample example for how to use onCreateView method with images, – Sheetal Suryan Feb 21 '12 at 11:23
  • 1
    Yes, let me see what I can dig out for you. – Mark Feb 21 '12 at 11:40
0

Sheetal,

I don't have my code in front of me at the minute but it should be something similar to the following:

public class MyFragment extends Fragment {
  private Resources resources;  // I load my images from different resources installed on the device
  private int id;

  public MyFragment() {
    setRetainInstance(true); // this will prevent the app from crashing on screen rotation
  }

  public MyFragment(Resources resources, int id) {
    this();  // this makes sure that setRetainInstance(true) is always called
    this.resources = resources;
    this.id = id;
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    ImageView imageView = (ImageView)inflater.infale(R.layout.fragmentview, container, false);
    imageView.setImageBitmap(BitmapFactory.decodeResource(resources, id));

    return imageView;
  }
}

This is pretty much off the top of my head, so it might not be exact, but it is pretty close.

If you need any more help just shout, don't forget to mark this answer as having helped you:).

Mark
  • 541
  • 2
  • 12
0

Sheetal,

As requested, I use the above code as follows:

In my FragmentActivity I do the following in the onCreate() method:

pager = (ViewPager)findViewById(R.id.pager);
imageAdapter = new MyPagerAdapter(this, pager, theResources, listOfIds.pageBitMapIds);
imageAdapter.setRecentListener(this);
pager.setAdapter(imageAdapter);

Then in my PagerAdapter I do the following:

@Override
public Object instantiateItem(ViewGroup container, int position) {
    MyFragment myFragment = new MyFragment(resources, resourceIds[position], recentListener, position);
    myFragments[position] = myFragment;
    return super.instantiateItem(container, position);
}

@Override
public Fragment getItem(int position) {
    return myFragments[position];
}

And then I use the code in my previous answer above.

This is obviously not complete code and it has been adapted from my actual code, but it should give you a good idea of what to do and where to do it.

Mark

Mark
  • 541
  • 2
  • 12
  • Mark, what instantiateItem returns i am getting error on this statement : return super.instantiateItem(container, position); // says : Cannot directly invoke the abstract method instantiateItem(View, int) for the type PagerAdapter – Sheetal Suryan Feb 22 '12 at 12:10
  • Mark, i have checked in my sample code in to github , please have look on it, it showing blank page , [link] git@github.com:sheetalsuryan/Samples.git – Sheetal Suryan Feb 23 '12 at 11:02
  • Sheetal, I've been really busy but I'll look at your code today and see what I can come up with. – Mark Feb 28 '12 at 08:48
  • Sheetal, you are missing the cache_dir setting from the strings.xml file. Please update the project. I don't want to guess what this value is. – Mark Feb 28 '12 at 09:00
  • Sheetal, can you give me rights to write to the github project, my username is arcotc. Thanks. – Mark Feb 28 '12 at 09:05
  • Thanks Mark , i have added you as collaborators, and i have also update the string.xml – Sheetal Suryan Feb 28 '12 at 10:52