Here is a very simple data class called People.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace BlogPostListActivity
{
class People
{
public string FirstName { get; set; }
public string LastName { get; set;}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace BlogPostListActivity
{
class People
{
public string FirstName { get; set; }
public string LastName { get; set;}
}
}
When the app runs, the People class will be used to create an object for each of the rows that will be displayed.
Android will manage the scrolling as it did with the Array Adapter, but this time we'll need to create an adapter that will hand off the information from the data objects when requested. Android will take care of getting them to the right place at the right time as the user scrolls up and down.
Our adapter class will inherit from the BaseAdapter and use a generic type <People> since that is the type of objects that will be displayed.
To function correctly, our adapter will have to override 3 key methods so that Android will have the information it needs at the proper time.
- Count - Return the total number of objects in the list.
- GetView - Android will pass the adapter a sequence number that it needs and this method will return a view that is populated with the particular object data that coincides with that sequence in the list of objects.
- GetItemId - Android will again pass the adapter a sequence number and this method can return an identifier which corresponds to that particular object. Usually this is just the same number as the sequence in the list of objects.
When the GetView method is called by Android, it will pass the location in memory of the View it needs your method to populate. As the user scrolls down the screen, new rows will appear and your method will be called to populate them with the corresponding data. In reality, Android is actually reusing the same memory locations over and over to save memory as the list scrolls. This makes little difference to your GetView method since it will be building its view wherever Android requests it to, but occasionally it will be passed a null location if this is the first time that that particular row is being populated. The method will have to test for this condition using an "if", and if it is null, "inflate" a new view in memory before populating it.
PeopleAdapter.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace BlogPostListActivity
{
// Inherit from the BaseAdapter class and use a generic type which matches the data objects
class PeopleAdapter:BaseAdapter<People>
{
private List<People> data; // a list of the data objects that will fill the rows
private Activity context; // a variable that will be passed that ties back to the activity which is using the adapter
public PeopleAdapter (Activity activity)
{
context = activity; // this is the calling activity that is using the adapter
// for simplicity, this example will just populate a list of People objects from a hard coded method when it is first created.
// In most cases, the objects will be filled from some more involved data source
data = PopulatePeopleData ();
}
public override People this[int position]
{
get { return data [position]; } //return a particular data object based on position
}
public override long GetItemId(int position)
{
return position; // this can be a unique id for each row, but returning the position is the easiest
}
public override int Count
{
get { return data.Count; } // this tells Android how many potential rows there will be
}
public override View GetView (int position, View rowView, ViewGroup parent)
{
// the rowView that is being filled may, or may not exist. If not, inflate a new one,
// otherwiser reuse the one passed in.
var view = rowView;
if (view == null) {
// ListActivities have built in listviews that fill the whole screen.
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace BlogPostListActivity
{
// Inherit from the BaseAdapter class and use a generic type which matches the data objects
class PeopleAdapter:BaseAdapter<People>
{
private List<People> data; // a list of the data objects that will fill the rows
private Activity context; // a variable that will be passed that ties back to the activity which is using the adapter
public PeopleAdapter (Activity activity)
{
context = activity; // this is the calling activity that is using the adapter
// for simplicity, this example will just populate a list of People objects from a hard coded method when it is first created.
// In most cases, the objects will be filled from some more involved data source
data = PopulatePeopleData ();
}
public override People this[int position]
{
get { return data [position]; } //return a particular data object based on position
}
public override long GetItemId(int position)
{
return position; // this can be a unique id for each row, but returning the position is the easiest
}
public override int Count
{
get { return data.Count; } // this tells Android how many potential rows there will be
}
public override View GetView (int position, View rowView, ViewGroup parent)
{
// the rowView that is being filled may, or may not exist. If not, inflate a new one,
// otherwiser reuse the one passed in.
var view = rowView;
if (view == null) {
// ListActivities have built in listviews that fill the whole screen.
// There is no need for an AXML Layout
// SimpleListItem2 is a predefined style with 2 text views, the first being bolder than the second
// no special AXML is required if this style is adequate
view = context.LayoutInflater.Inflate (Android.Resource.Layout.SimpleListItem2, null);
}
var people = data [position]; //get the people object that corresponds to this position
// locate the 2 predefined text views and load the data from the object into them
view.FindViewById<TextView> (Android.Resource.Id.Text1).Text = people.LastName;
view.FindViewById<TextView> (Android.Resource.Id.Text2).Text = people.FirstName;
return view; // return the formated view
}
private List<People> PopulatePeopleData() {
// this is just done in this demo for simlicity to create the People objects
return new List<People> ()
{
new People { FirstName = "Anita", LastName = "Drink" },
new People { FirstName = "Amanda", LastName = "Reconwith" },
new People { FirstName = "Warren", LastName = "Peace" },
new People { FirstName = "Rhonda", LastName = "Corner" },
new People { FirstName = "Karen", LastName = "Feeding" },
new People { FirstName = "Rufus Lee", LastName = "King" },
new People { FirstName = "Winston", LastName = "Payne" },
new People { FirstName = "Marian", LastName = "Haste" },
new People { FirstName = "Augusta", LastName = "Wind" },
new People { FirstName = "Eileen", LastName = "Dover" },
new People { FirstName = "Wendy", LastName = "Lottery" },
new People { FirstName = "Betty", LastName = "Wont" },
new People { FirstName = "Marty", LastName = "Graw" }
};
}
}
}
// SimpleListItem2 is a predefined style with 2 text views, the first being bolder than the second
// no special AXML is required if this style is adequate
view = context.LayoutInflater.Inflate (Android.Resource.Layout.SimpleListItem2, null);
}
var people = data [position]; //get the people object that corresponds to this position
// locate the 2 predefined text views and load the data from the object into them
view.FindViewById<TextView> (Android.Resource.Id.Text1).Text = people.LastName;
view.FindViewById<TextView> (Android.Resource.Id.Text2).Text = people.FirstName;
return view; // return the formated view
}
private List<People> PopulatePeopleData() {
// this is just done in this demo for simlicity to create the People objects
return new List<People> ()
{
new People { FirstName = "Anita", LastName = "Drink" },
new People { FirstName = "Amanda", LastName = "Reconwith" },
new People { FirstName = "Warren", LastName = "Peace" },
new People { FirstName = "Rhonda", LastName = "Corner" },
new People { FirstName = "Karen", LastName = "Feeding" },
new People { FirstName = "Rufus Lee", LastName = "King" },
new People { FirstName = "Winston", LastName = "Payne" },
new People { FirstName = "Marian", LastName = "Haste" },
new People { FirstName = "Augusta", LastName = "Wind" },
new People { FirstName = "Eileen", LastName = "Dover" },
new People { FirstName = "Wendy", LastName = "Lottery" },
new People { FirstName = "Betty", LastName = "Wont" },
new People { FirstName = "Marty", LastName = "Graw" }
};
}
}
}
The ListActivity is as follows.
MainActivity.cs
using System;
using System.Collections.Generic;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
namespace BlogPostListActivity
{
[Activity (Label = "BlogPostListActivity", MainLauncher = true)]
//Inherit from the ready made ListActivity Class for simplicity
public class MainActivity : ListActivity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// create a new instance of the PeopleAdapter and pass a reference
// to this activity so that the adapter
// can inflate new rows in the in the built-in
// ListView that comes with a ListActivity class
ListView.Adapter = new PeopleAdapter (this);
}
}
}
using System.Collections.Generic;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
namespace BlogPostListActivity
{
[Activity (Label = "BlogPostListActivity", MainLauncher = true)]
//Inherit from the ready made ListActivity Class for simplicity
public class MainActivity : ListActivity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// create a new instance of the PeopleAdapter and pass a reference
// to this activity so that the adapter
// can inflate new rows in the in the built-in
// ListView that comes with a ListActivity class
ListView.Adapter = new PeopleAdapter (this);
}
}
}
SimpleListItem2 Style
Changing the adapter to use the TwoLineListItem style produces the following.
view =
context.LayoutInflater.Inflate (Android.Resource.Layout.TwoLineListItem, null);
TwoLineListItem Style
The SimpleListItem1 Style shown in the blog post on the ArrayAdapter can also be used, but it will only support the first text item. There is also an ActivityListItem style which includes an image that will be covered in a later post.
Filtering and sorting can be performed by a CustomAdapter before it is displayed. For example, modifying the PeopleAdapter to use a linq expression to sort on last name will re-order the data.
//data = PopulatePeopleData ();
data = (from p in PopulatePeopleData ()
orderby p.LastName
select p).ToList ();
data = (from p in PopulatePeopleData ()
orderby p.LastName
select p).ToList ();