Android Monodroid-根据GREF限制将数据传递到ListView
C、 Android的Mono。我需要将大部分组合数据输出到ListView中。为了实现这一点,我对适配器使用了以下明显的方法:Android Monodroid-根据GREF限制将数据传递到ListView,android,mono,xamarin.android,Android,Mono,Xamarin.android,C、 Android的Mono。我需要将大部分组合数据输出到ListView中。为了实现这一点,我对适配器使用了以下明显的方法: class ItemInfo { public string Id; public string Name; public string Description; public int Distance; //Some more data } class ItemAdapter : ArrayAdapter<Item
class ItemInfo
{
public string Id;
public string Name;
public string Description;
public int Distance;
//Some more data
}
class ItemAdapter : ArrayAdapter<ItemInfo>
{
public WorldItemAdapter (Context context, int textViewResourceId, List<WorldItemInfo> items) :
base(context, textViewResourceId, items)
{
}
//...
public override View GetView (int position, View convertView, ViewGroup parent)
{
//Some stuff to format ListViewItem
}
}
public class OutputActivity : Activity
{
ListView _listView;
//...
void FillList (object SomeParameters)
{
var adaptedList = someDataSource.Where().Join().Union().//anything can be imagined
.Select ((item, item2, item3) =>
new ItemInfo (){
Id = item.Id,
Name = item.Name,
Description = String.Format(..., item2, item3),
Distance = ...,
//so on
}
).OrderBy ((arg) => arg.Name).ToList ();
_listView.Adapter = new ItemAdapter (this, Resource.Layout.ListItemFormat, adaptedList ());
}
}
这个很好用。。。直到我开始频繁刷新我的ListView。例如,如果我通过刷新视图生成了许多ItemInfo,我很快就达到了GREF限制,意外的NullReferenceExceptions部分,我的应用程序崩溃。查看Android日志,我可以看到数千个Android.Runtime.IJavaObject对象,它们超出了GREF限制
根据Mono VM+Dalvik VM bridge的定义,我可以理解,我的ItemInfo需要传递给Dalvik VM,包装到IJavaObject,并由本机环境在ListView中格式化-这会创建GREF。只要垃圾收集是一个不确定的过程,如果我多次调用FillList,旧的、已经使用的ItemInfo就会留在内存中,发生泄漏
我怎样才能避免泄漏?或者,有没有其他方法可以将大部分格式化数据输出到ListView?我试过:
我不能减少ItemInfo的数量,只要我需要以某种方式放置数据。
只要我的ItemInfo不是IJavaObject,我就无法理解这一点。
作为一种临时解决方案,每次需要刷新列表时,我都会调用GC.Collect,但这看起来不是一种干净的方法。另外,若我需要将2个以上的对象输出到列表中,这也并没有帮助。
在我的项目中,我也遇到了同样的问题 ItemInfo是托管对象,所以您不需要对它做任何事情,GC会在必要时收集它。 ListView不会一次加载每个列表项的视图,所以您可以控制创建视图的数量并对其进行处理。 这是我的解决办法 我已经从BaseAdapter中删除了一些不必要的重写,所以如果它要求您实现它们,请不要害怕
class CustomViewAdapter : BaseAdapter<ItemInfo>
{
private readonly Context _context;
private IList<ItemInfo> _items;
private readonly IList<View> _views = new List<View>();
public CustomViewAdapter(IntPtr handle)
: base(handle)
{
}
public CustomViewAdapter (Context context, IList<ItemInfo> objects)
{
_context = context;
_items = objects;
}
private void ClearViews()
{
foreach (var view in _views)
{
view.Dispose();
}
_views.Clear();
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var inflater = LayoutInflater.From(_context);
var row = convertView ?? inflater.Inflate(Resource.Layout.ListItemView, parent, false);
/// set view data
if(!_views.Contains(row))
_views.Add(row);
return row;
}
public override int Count
{
get { return _items == null ? 0 : _items.Count; }
}
public override void Dispose()
{
ClearViews();
base.Dispose();
}
}
用法示例
找到答案。我从Java.Lang.Object显式继承了ItemInfo类,现在可以在不再需要该对象时调用Dispose。这将杀死泄漏的GREFs。谢谢,这是一个非常好的概念,我将考虑在将来使用它,但这显然不是我的问题。我对视图没有任何问题——事实上,当活动完成时,它们应该由本机代码自动与ListView一起处理,所以这里不需要关心我。我需要以某种方式处理ItemInfo。使用延迟加载实体或像这样重用现有项,但使用ItemInfo如何。var行=转换视图??inflater.InflateResource.Layout.ListItemView,父级,false;找到了另一个解决方案。我从Java.Lang.Object显式继承了ItemInfo类,现在可以在不再需要该对象时调用Dispose。这会杀死泄漏的GREFs
[Activity]
public class MessagesActivity : Activity
{
private CustomViewAdapter _adapter;
protected override void OnCreate(Android.OS.Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.ListView);
_adapter=new CustomViewAdapter(this,Enumerable.Empty<ItemInfo>);
FindViewById<ListView>(Resource.Id.list).Adapter=_adapter;
}
public override void Finish()
{
base.Finish();
if(_adapter!=null)
_adapter.Dispose();
_adapter=null;
}
}