2015-10-13 2 views
1

У меня есть приветственная деятельность, которая использует ViewPager и пользовательский LayoutPagerAdapter. Дело в том, что макеты содержат довольно большие изображения, а сохранение их в памяти - это не то, что желательно.Управление памятью при использовании PageViewer и LayoutPagerAdapter

Вот почему я рециркуляция их, когда OnDestroyItem называется.

Когда я делаю повторное использование, хотя оно и прерывает приложение. В основном отключает виртуальную машину.

Вот код для LayoutPagerAdapter.

public class LayoutPagerAdapter : PagerAdapter 
    { 
     Context m_context; 
     readonly int[] m_slideLayoutResourceIds; 

     public LayoutPagerAdapter(Context context, int[] slideLayoutResourceIds) 
     { 
      m_context = context; 
      m_slideLayoutResourceIds = slideLayoutResourceIds; 
     } 

     public override Java.Lang.Object InstantiateItem(ViewGroup container, int position) 
     { 
      var inflater = LayoutInflater.From(m_context); 

      var view = inflater.Inflate(m_slideLayoutResourceIds[position], container, false); 

      container.AddView(view); 

      return view; 
     } 

     public override void DestroyItem(ViewGroup container, int position, Java.Lang.Object objectValue) 
     { 
      var bitmapDrawable = (BitmapDrawable)((View)objectValue).FindViewById<ImageView>(Resource.Id.welcomeBackgroundImage).Drawable; 
      bitmapDrawable.Bitmap.Recycle(); 

      container.RemoveView((View)objectValue); 
     } 

     #region implemented abstract members of PagerAdapter 

     public override bool IsViewFromObject(View view, Java.Lang.Object objectValue) 
     { 
      return view == objectValue; 
     } 

     public override int Count 
     { 
      get 
      { 
       return m_slideLayoutResourceIds.Length; 
      } 
     } 

     #endregion 
    } 

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

var bitmapDrawable = (BitmapDrawable)((View)objectValue).FindViewById<ImageView>(Resource.Id.welcomeBackgroundImage).Drawable; 
       bitmapDrawable.Bitmap.Recycle(); 

Вот код действия для полноты.

[Activity(MainLauncher = true, Label = "")]   
    public class WelcomeActivity : Activity 
    { 
     ViewPager m_welcomeViewPager; 
     LayoutPagerAdapter m_layoutPagerAdapter; 
     TextView m_welcomeSkipButton; 
     CirclePageIndicator m_circlePageIndicator; 

     protected override void OnCreate(Bundle bundle) 
     { 
      base.OnCreate(bundle); 

      SetContentView(Resource.Layout.Welcome); 

      m_circlePageIndicator = FindViewById<CirclePageIndicator>(Resource.Id.welcomeCirclePageIndicator); 
      m_welcomeSkipButton = FindViewById<TextView>(Resource.Id.welcomeSkipButton); 
      m_welcomeViewPager = FindViewById<ViewPager>(Resource.Id.welcomeViewPager); 

      m_layoutPagerAdapter = new LayoutPagerAdapter(this, 
       new [] 
       { 
        Resource.Layout.welcome_slide_1, 
        Resource.Layout.welcome_slide_2, 
        Resource.Layout.welcome_slide_3, 
        Resource.Layout.welcome_slide_4, 
        Resource.Layout.welcome_slide_5, 
        Resource.Layout.welcome_slide_6 
       }); 

      m_welcomeViewPager.Adapter = m_layoutPagerAdapter; 
      m_circlePageIndicator.SetViewPager(m_welcomeViewPager); 
      m_circlePageIndicator.SetCurrentItem(0); 
     } 

     protected override void OnResume() 
     { 
      base.OnResume(); 

      m_welcomeSkipButton.Click += WelcomeSkipButtonClick; 
     } 

     void WelcomeSkipButtonClick(object sender, System.EventArgs e) 
     { 
      // TODO 
     } 

     protected override void OnPause() 
     { 
      base.OnPause(); 

      m_welcomeSkipButton.Click -= WelcomeSkipButtonClick; 
     } 

     protected override void OnDestroy() 
     { 
      base.OnDestroy(); 

      if (m_circlePageIndicator != null) 
      { 
       m_circlePageIndicator.Dispose(); 
       m_circlePageIndicator = null; 
      } 

      if (m_layoutPagerAdapter != null) 
      { 
       m_layoutPagerAdapter.Dispose(); 
       m_layoutPagerAdapter = null; 
      } 

      if (m_welcomeSkipButton != null) 
      { 
       m_welcomeSkipButton.Dispose(); 
       m_welcomeSkipButton = null; 
      } 

      if (m_welcomeViewPager != null) 
      { 
       m_welcomeViewPager.Dispose(); 
       m_welcomeViewPager = null; 
      } 
     } 
    } 

Вот выход приложения при прокрутке макетов, а затем выключение VM.

[dalvikvm-heap] Grow heap (frag case) to 24.469MB for 2810896-byte allocation 
[dalvikvm-heap] Grow heap (frag case) to 30.500MB for 6324496-byte allocation 
[dalvikvm-heap] Grow heap (frag case) to 24.487MB for 2810896-byte allocation 
[dalvikvm-heap] Grow heap (frag case) to 30.517MB for 6324496-byte allocation 
[dalvikvm-heap] Grow heap (frag case) to 25.001MB for 2810896-byte allocation 
[dalvikvm-heap] Grow heap (frag case) to 31.032MB for 6324496-byte allocation 
[AndroidRuntime] Shutting down VM 

Я бы ожидал, что приложение просто повторит создание макетов при попытке прокрутки назад. Почему рециркуляция будет препятствовать этому?

+0

Вы пробовали прочитать через http://developer.xamarin.com/recipes/android/resources/general/load_large_bitmaps_efficiently/, также вы можете изучить использование WeakReferences. –

ответ

0

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

Я удалил линию и сильно изменил размеры изображений. В моем случае от 250 кб до 75 кб, что в основном решило все мои проблемы с памятью.

1

Возможно, вы захотите проверить эту статью о управлении памятью Bitmap (https://developer.android.com/training/displaying-bitmaps/manage-memory.html). Если вы ориентируетесь на Android 3.0 или выше, существует другая парадигма, используемая для утилизации растровых изображений вместо ручного вызова recycle().

Поскольку вы используете большие растровые изображения, я настоятельно рекомендую использовать библиотеку, такую ​​как Picasso или Glide для загрузки изображений. При этом многие заботливые работы позаботились о вас, и вы можете легко кэшировать изображения на высоком уровне, если это необходимо. Еще один возможный совет, если изображение не является фотографией или вам не нужен альфа-канал/более высокая глубина цвета, попробуйте использовать RGB565 против ARGB8888 для меньшего использования памяти.

Смежные вопросы