C#, Mono for Android. I need to output a large portion of combined data into ListView. To achieve this, I use the following obvious approach with Adapter:
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 ());
}
}
This works very fine... until I start to refresh my ListView frequently. If I generate many ItemInfo's (by refreshing my view, for example), I reach GREF limit soon (described here, "Unexpected NullReferenceExceptions" section), and my application crashes. Looking into Android log, I can see thousands of Android.Runtime.IJavaObject objects, which overflow GREF limit.
According to concepts of Mono VM + Dalvik VM bridge I can understand, that my ItemInfo's need to be passed to Dalvik VM, wrapped to IJavaObject and to be formatted in ListView by native environment - this creates GREF's. As long as garbage collecting is a non-determined process, if I call FillList() many times, old, already used ItemInfo's stay into memory, leaking.
How can I avoid leaking? Or, possible, is there another way to output large portions of formatted data into ListView? I tried:
- I can't reduce the number of ItemInfo's, as long as I need to place my data somehow.
- I can't follow this advice, as long as my ItemInfo is not an IJavaObject.
- As a temporarily solution, I call GC.Collect() every time I need to refresh list, but this looks not a clean way. Also, if I need to output more than 2к objects into list, this doesn't help.