Outofmemeoryerror (viewpager + imagesviews)

Я показываю 150+ изображений в viewpager, когда размер страницы пересек 70, приложение сбой, все изображения загружаются из сети, и я получил [link]: Странная проблема с памятью при загрузке изображения в объект Bitmap

и я перерабатываю его всякий раз, когда прокрутка страницы достигает 4,

для 70-страничного приложения, использующего 200 МБ памяти.

Мне нужна помощь от вас, как с ней справиться

Мне нужно показать все страницы с прокруткой...

i также использовал Runtime.getRuntime(). gc();

- любой способ освободить память, если память приложения достигает 50+ МБ

заблаговременно

Ответ 1

Полное решение можно найти ниже, важными являются строки в методе destroyItem:

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

    }

Ответ 2

Я думаю, что это происходит потому, что у вас есть утечка памяти, дважды проверьте свои переменные, не используйте статические vars для чего-либо большого, используйте final, когда это возможно, сделайте всех членов закрытыми.

Я предлагаю вам совершить фиксацию (или сохранить текущий код), а затем попытаться выполнить то, что я спросил, и посмотреть, исправляет ли он это.

образец кода позволит мне рассказать вам, есть ли у вас утечки памяти, возможно, вы можете разместить код где-нибудь как в github или google code

В нижней строке: вы можете делать все правильно, но переменная по-прежнему содержит ссылку на ваши изображения, чтобы сборщик мусора не мог их трогать.

Я знаю, что у вас болит утечка памяти, но, пожалуйста, не беспокойтесь, это случается с лучшими из лучших, потому что так легко случиться.

ПРИМЕЧАНИЕ. Независимо от того, насколько большой объем данных, загружаемых из сетевых приложений, не требуется больше, чем размер 1 файла, если он правильно обработан.

Спасибо

Ответ 3

Шитал,

Посмотрев на свой код, вы можете попробовать следующее:

@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;
}

Это должно освободить imageView для сбора мусора.

Ответ 4

Загружаете ли вы изображения в режиме просмотра onCreateView()?

Похоже, что эта платформа заботится о требованиях к управлению памятью при выполнении этого способа. Я попытался загрузить мои изображения в свой FragmentPageAdapter, передав их в мой конструктор фрагментов, предварительно загруженный или как часть метода instaniateItem Fragment, но оба они дали мне проблему, с которой вы столкнулись. В конце я передал информацию, необходимую для загрузки каждого изображения в конструктор фрагмента, а затем использовал эти данные в методе onCreateView().

Марк

Ответ 5

Шитал,

У меня нет моего кода передо мной в минуту, но это должно быть что-то похожее на следующее:

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;
  }
}

Это в значительной степени от верхушки головы, поэтому это может быть не совсем точно, но это довольно близко.

Если вам нужна дополнительная помощь, просто кричите, не забудьте отметить этот ответ, как помогли вам:).

Ответ 6

Шитал,

В соответствии с запросом я использую вышеуказанный код следующим образом:

В моем FragmentActivity я делаю следующее в методе onCreate():

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

Затем в моем PagerAdapter я делаю следующее:

@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];
}

И затем я использую код в своем предыдущем ответе выше.

Это, очевидно, не полный код, и он был адаптирован из моего фактического кода, но он должен дать вам хорошее представление о том, что делать и где это делать.

Марк