Using A Custom Array Adapter

Chris Harte2015 Top Expert (Most Article Points)
CERTIFIED EXPERT
A developer with over twenty years experience. Started on mainframes and Cobol, now on mobiles and Android.
Published:
Displaying an arrayList in a listView using the default adapter is rarely the best solution. To get full control of your display data, and to be able to refresh it after editing, requires the use of a custom adapter.
I have a database with lots of stored information. I extract it into an array and display it using a listView. All nice and simple, except I want to limit the amount of data I am displaying. The information is editable and the listView does not update the display with the new, edited, item. To overcome these limitations I am going to use a custom adapter.

I have some data loaded from a local database; each item is a data object called Sticky_notes. These are collected into an arrayList and I want to display them in a listView. The list and default adapter looks like this:

 
    private ArrayList<Sticky_notes>    notes;
                          private ArrayAdapter<Sticky_notes> my_adapter;

Open in new window


The adapter is then initialised and used:
 
    my_adapter = new ArrayAdapter<Sticky_notes>(this,
                                                        android.R.layout.simple_list_item_1,
                                                        notes);
                      
                          list_view.setAdapter(my_adapter);

Open in new window

This will display all the fields in my database. But I wanted to show only fields that are relevant. This is what my data class looks like
 
public class Sticky_notes
                      {
                          private String row_id;
                          private String title;
                          private String note;
                      
                          public Sticky_notes (String row_id, String title, String note)
                          {
                              super();
                              this.row_id = row_id;
                              this.title = title;
                              this.note = note;
                          }
                      
                          public String get_title()
                          {
                              return title;
                          }
                          
                          
                          public String get_note()
                          {
                              return note;
                          }    
                      
                      }    

Open in new window


Each item was a Sticky_notes stored in an SQLite database. I have extracted all the data into the ArrayList consisting of Sticky_notes. I only want to display 'title' and 'note'; the row_id is used internally for editing so nobody needs to see it. When you click on an item you can edit it. The displayed list view then has to be refreshed. This is handled through the adapter. 

Create an array adapter as a class that extends the arrayAdapter. This will have its constructor and one implemented method of getView(); 
 
private static class Note_Adapter extends ArrayAdapter<Sticky_notes>
                      {
                          public Note_Adapter(Activity context, ArrayList<Sticky_notes> data)
                           {
                               // The layout containing the listView where the data is going to end up.
                               super(context, R.layout.activity_sticky, data);
                           }
                      
                           @Override public View getView(int position, View convertView, ViewGroup parent)
                          {
                          }
                      
                      }

Open in new window

The listView typically has far more data than the number of displayed rows. When the list is scrolled then the rows and their associated data are out of the visible area. The objects for the rows can be reused for the newly visible rows. This is what the getView method is for. This method will use a local static class that will hold the view data, I have called this class Note_holder.
 
private static class Note_Adapter extends ArrayAdapter<Sticky_notes>
                      {
                           // The class for holding the view data
                           private static class Note_Holder
                           {
                               TextView txtNote;
                               TextView txtTitle;
                           }
                      
                          public Note_Adapter(Activity context, ArrayList<Sticky_notes> data)
                           {
                               // The layout containing the listView where the data is going to end up.
                               super(context, R.layout.activity_sticky, data);
                           }
                      
                           @Override public View getView(int position, View convertView, ViewGroup parent)
                          {
                          }
                      
                      }

Open in new window


The Note_holder will hold the reference to the relevant view in your layout, which will be set using the setTag() method. When there is no current view the XML is inflated into convertView, using findViewById to populate it. If it is already being used we will get a convertView object that will update the Note_holder via the getTag() method. Sounds complex because it is, but it is much faster than using findViewById() every single time.

In the getView method instantiate the Note_holder, test the convertView object and if null then assign the new and relevant attributes. The item that was clicked is passed in the 'position' parameter. If convertView is not null, reuse it.
 
private static class Note_Adapter extends ArrayAdapter<Sticky_notes>
                      {
                      
                           private static class Note_Holder
                           {
                               TextView txtNote; // The data is made up of Note and Title
                               TextView txtTitle;
                           }
                      
                          public Note_Adapter(Activity context, ArrayList<Sticky_notes> data)
                           {
                               // The layout containing the listView where the data is going to end up.
                               super(context, R.layout.activity_sticky, data);
                           }
                      
                           @Override public View getView(int position, View convertView, ViewGroup parent)
                          {
                      
                               Note_Holder holder;  // The viewed data
                      
                               if (convertView == null) 
                                  {
                                     // There was not existing object, so inflate the xml into it.
                                      holder = new Note_Holder();
                      
                                      // Inflate the layout containing the textViews that I want to
                                      // add to the listView
                                      LayoutInflater inflater = LayoutInflater.from(getContext());
                                      convertView = inflater.inflate(R.layout.note_item, parent, false);
                      
                                      holder.txtTitle = (TextView) convertView.findViewById(R.id.item_title);
                                      holder.txtNote = (TextView) convertView.findViewById(R.id.item_note);
                      
                                      //The convertView has been used, so set the tag with the view information
                                      convertView.setTag(holder);
                      
                                  }
                                  else
                                  {
                                      // We have a convertView, so get the view information from the tag.
                                      holder = (Note_Holder) convertView.getTag();
                                  }
                      
                                  // Fill the Note_holder class with data that has been passed from the listView
                                  Sticky_notes temp_data = getItem(position);
                      
                                  String title = temp_data.get_title(); //The get methods from the data class.
                                  String note = temp_data.get_note();
                      
                                  holder.txtTitle.setText("\n  " + title);
                                  holder.txtNote.setText(" " + note);
                      
                                  return convertView;
                      
                          }
                      
                      }

Open in new window


This adapter is now ready to be used to display your data. Comment out the default adapter and use this new one.
 
    /* my_adapter = new ArrayAdapter<Sticky_notes>(this,
                                                           android.R.layout.simple_list_item_1,
                                                           notes); 
                          */
                      
                          my_adapter = new Note_Adapter(this, notes);
                      
                          list_view.setAdapter(my_adapter);

Open in new window

When the variable 'notes' has been populated with the contents of your database the new adapter will display it to the available amount of screen. When you create your onClickListener to enable editing of your item you can use this adapter to access your data:
 
       list_view.setOnItemClickListener(new OnItemClickListener()
                             {
                                 @Override 
                                 public void onItemClick(AdapterView<?> parent, View view, int position, long id)
                                 {
                                      //Use the adapter to get the item at 'position'
                                      String note_body = my_adapter.getItem(position).get_note();
                      
                                      //This will edit the clicked item.
                                      Intent i = new Intent("app.simple_sticky.EDIT_NOTE");           
                                      i.putExtra("note", note_body);                
                                      startActivity(i);
                                  }
                              });

Open in new window


What you will find now is that after you have edited your data, the display will not use the new information. So before setting the adapter, use the library methods clear() and addAll() to rebuild the array. In your onCreate() and onResume() methods you will need
 
 my_adapter.clear(); // empty the adapter
                       my_adapter.addAll(notes); // Load it up with the updated arraylist.
                       list_view.setAdapter(my_adapter);

Open in new window

This will display your data from the database and, more importantly, refresh the display after editing without having to reload it from the database.
1
2,302 Views
Chris Harte2015 Top Expert (Most Article Points)
CERTIFIED EXPERT
A developer with over twenty years experience. Started on mainframes and Cobol, now on mobiles and Android.

Comments (0)

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.