2017-06-24 6 views
0

こんにちはすべてのプログラマー。 私はAndroid用のアプリケーションをVisual Studio Xamarinで作成していますが、メモリに問題があります。私のアプリのユーザーでは、国の電話のプレフィックスを選択する必要があります。このためのUIはListViewの警告ダイアログです。私は拡張アダプタでListViewを塗りつぶします。AlertDialogのimageViewとTextViewを使用したListViewは、メモリを使い果たし、Java.Lang.OutOfMemoryErrorを取得します。

internal class CountryListViewHolderClass : Java.Lang.Object 
    { 
     internal Action viewClicked { get; set; } 
     internal TextView countryCodeView; 
     internal ImageView countryImageView; 
     internal ImageView countryCheckView; 
     public void initialize(View view) 
     { 
      view.Click += delegate 
      { 
       viewClicked(); 
      }; 
     } 
    } 
    public class CountryInfo 
    { 
     public string _flag { get; private set; } 
     public string _code { get; private set; } 
     public string _prefix { get; private set; } 
     public CountryInfo(string flag, string code, string prefix) 
     { 
      _flag = flag; 
      _code = code; 
      _prefix = prefix; 
     } 
    } 
    public class CountryListAdapter : BaseAdapter<string> 
    { 
     Activity _context; 
     string[] _countryCode; 
     string[] _countryPrefix; 
     string[] _countryFlag; 
     internal event Action<CountryInfo> actionCountrySelected; 
     public CountryListAdapter(Activity context, string[] countryCode, string[] countryFlag, string[] countryPrefix) 
     { 
      _context = context; 
      _countryCode = countryCode; 
      _countryFlag = countryFlag; 
      _countryPrefix = countryPrefix; 
     } 
     public override View GetView(int position, View convertView, ViewGroup parent) 
     { 
      CountryListViewHolderClass countryListViewHolderClass; 
      View view; 
      view = convertView; 
      Android.Graphics.Color viewBg; 
      if (view == null) 
      { 
       view = _context.LayoutInflater.Inflate(Resource.Layout.CountryListItem, parent, false); 
       countryListViewHolderClass = new CountryListViewHolderClass(); 
       countryListViewHolderClass.countryCodeView = view.FindViewById<TextView>(Resource.Id.countryCodeText); 
       countryListViewHolderClass.countryImageView = view.FindViewById<ImageView>(Resource.Id.countryFlagImg); 
       countryListViewHolderClass.countryCheckView = view.FindViewById<ImageView>(Resource.Id.countryCheckImage); 
       countryListViewHolderClass.initialize(view); 
       view.Tag = countryListViewHolderClass; 
      } 
      else 
      { 
       countryListViewHolderClass = (CountryListViewHolderClass)view.Tag; 
      } 

      countryListViewHolderClass.countryCodeView.Text = "(+" + _countryPrefix[position] + ") " + _countryCode[position]; 
      Stream flag = _context.Resources.Assets.Open("cflags/" + _countryFlag[position] + ".png"); 
       countryListViewHolderClass.countryImageView.SetImageDrawable(Drawable.CreateFromStream(flag, _countryFlag[position])); 
       flag.Dispose(); 
       flag.Close(); 
      } 
      countryListViewHolderClass.viewClicked =() => 
      { 
       if (actionCountrySelected != null) 
       { 
        for (int i=0; i < parent.ChildCount; i++) 
        { 
         View otherView = parent.GetChildAt(i); 
         ImageView checkIcon = otherView.FindViewById<ImageView>(Resource.Id.countryCheckImage); 
         checkIcon.Alpha = 0; 
        } 
        countryListViewHolderClass.countryCheckView.Alpha = 1; 
        CountryInfo result = new CountryInfo(_countryFlag[position], _countryCode[position], _countryPrefix[position]); 
        actionCountrySelected(result); 
       } 
      }; 
      return view; 
     } 
    } 

このアダプターは、メインアクティビティーでListViewを満たすために使用します。このリストビューでAlertDialogを開くと、すべてが問題ありません。 2回目に同じAlertDialogを開くと、Java.Lang.OutOfMemoryErrorがスローされます。ここでアダプタを作成してListViewに送信するコード

void BindCountryList() 
     { 
      string[] countryCodes = Resources.GetStringArray(Resource.Array.countries_names); 
      string[] countryPrefixes = Resources.GetStringArray(Resource.Array.countries_iso_prefixes); 
      string[] countryFlags = Resources.GetStringArray(Resource.Array.countries_iso_codes); 
      if (countryListAdapter != null) 
      { 
       countryListAdapter.actionCountrySelected -= CountrySelected; 
       countryListAdapter = null; 
      } 
      countryListAdapter = new CountryListAdapter(this, countryCodes, countryFlags, countryPrefixes); 
      countryListAdapter.actionCountrySelected += CountrySelected; 
      Stream flag = Resources.Assets.Open("cflags/tr.png"); 
      countryCodeSelectButton.SetImageDrawable(Drawable.CreateFromStream(flag, "tr.png")); 
      flag.Dispose(); 
      flag.Close(); 
      phoneCountryPrefix.Text = "+90"; 
     } 
void CountrySelected(CountryInfo countryInfo) 
     { 
      phoneCountryPrefix.Text = "+"+countryInfo._prefix; 
      phonePrefix = countryInfo._prefix; 
      countrySelectAlert.Cancel(); 
      Stream flag = Resources.Assets.Open("cflags/" + countryInfo._flag + ".png"); 
      countryCodeSelectButton.SetImageDrawable(Drawable.CreateFromStream(flag, countryInfo._flag)); 
      flag.Close(); 
      string toast = string.Format("The prefix is {0}", countryInfo._code); 
      Toast.MakeText(this, toast, ToastLength.Long).Show(); 
     } 

私は本当にメモリリークがどこにあるのか分かりません。すべての助けに感謝します。

+0

getViewメソッド機能を変更します。これは特に 'Bitmap'のような大きなオブジェクトに必要です。メモリから解放することを検討する必要があるオブジェクトの完全なガイドがあります(https://developer.xamarin.com/guides/cross-platform/deployment,_testing,_and_metrics/memory_perf_best_practices/)。 – Demitrian

+0

@Demitrian Solutionにあなたは助けになると示唆しました。ありがとうございました。あなたが同意するなら、私は以下の質問の答えとしてそれを書いていきます。 –

+0

それが働いたことを知っておいてよかった、Adeptus – Demitrian

答えて

0

提案通りDemitrian私はIDisposableパターンを使用しました。だから私は、CountryListAdapterクラスあなたは `IDisposable`パターンを実装検討する必要があり、このよう

public override View GetView(int position, View convertView, ViewGroup parent) 
{ 
    CountryListViewHolderClass countryListViewHolderClass; 
    View view; 
    view = convertView; 
    if (view == null) 
    { 
     view = _context.LayoutInflater.Inflate(Resource.Layout.CountryListItem, parent, false); 
     countryListViewHolderClass = new CountryListViewHolderClass(); 
     countryListViewHolderClass.countryCodeView = view.FindViewById<TextView>(Resource.Id.countryCodeText); 
     countryListViewHolderClass.countryImageView = view.FindViewById<ImageView>(Resource.Id.countryFlagImg); 
     countryListViewHolderClass.countryCheckView = view.FindViewById<ImageView>(Resource.Id.countryCheckImage); 
     countryListViewHolderClass.initialize(view); 
     view.Tag = countryListViewHolderClass; 
    } 
    else 
    { 
     countryListViewHolderClass = (CountryListViewHolderClass)view.Tag; 
    } 

    countryListViewHolderClass.countryCodeView.Text = "(+" + _countryPrefix[position] + ") " + _countryCode[position]; 
    StreamReader reader=null; 
    try 
    { 

     reader = new StreamReader(_context.Resources.Assets.Open("cflags/" + _countryFlag[position] + ".png")); 
     countryListViewHolderClass.countryImageView.SetImageDrawable(Drawable.CreateFromStream(reader.BaseStream, _countryFlag[position])); 
    } 
    finally 
    { 
     if (reader != null) 
     { 
      reader.Dispose(); 
     } 
    } 
    countryListViewHolderClass.viewClicked =() => 
    { 
     if (actionCountrySelected != null) 
     { 
      for (int i=0; i < parent.ChildCount; i++) 
      { 
       View otherView = parent.GetChildAt(i); 
       ImageView checkIcon = otherView.FindViewById<ImageView>(Resource.Id.countryCheckImage); 
       checkIcon.Alpha = 0; 
      } 
      countryListViewHolderClass.countryCheckView.Alpha = 1; 
      CountryInfo result = new CountryInfo(_countryFlag[position], _countryCode[position], _countryPrefix[position]); 
      actionCountrySelected(result); 
     } 
    }; 
    return view; 
} 
関連する問題