0
向所有程序員致意。 雖然我在Visual Studio Xamarin中爲Android創建應用程序,但我發現內存有問題。在我的應用程序用戶需要選擇國家電話前綴。用於此的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。如果我用這個ListView打開AlertDialog,一切正常。如果我第二次打開相同的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();
}
我真的不明白哪裏是內存泄漏。所有的幫助將不勝感激。
你可能要考慮執行'IDisposable'模式的功能。對於像「位圖」這樣的大對象來說,這是特別需要的。你可以找到一個完整的指導,你需要考慮從內存中釋放哪些對象[這裏](https://developer.xamarin.com/guides/cross-platform/deployment,_testing,_and_metrics/memory_perf_best_practices/)。 – Demitrian
對@Demitrian您建議的解決方案是有幫助的。謝謝。如果你同意,我會將它寫爲下面我的問題的答案。 –
很高興知道它的工作,Adeptus – Demitrian