Learn Android Development For Beginners

Adapters and AdapterView

In Android Adapters are bridge between the Adapter View (e.g. ListView, GridView) and underlying data for that view. The Adapter is also responsible for making a View for each item in the result set. Android separates the responsibilities of showing data into list controls and adapters. The Adapter is responsible for creating child views used to represent each item and providing access to the underlying data.

In Android List controls that supports Adapter binding extend the android.widget.AdapterView class. ListView, GridView, Spinner and Gallery extends the AdapterView.

adpter view diagram

As you can see in diagram, the AdapterView class is inherited form ViewGroup class and ListView, GridView and Spinner classes are derived from AdapterView class.

The Adapter extend the BaseAdapter class. It manages the data for an AdapterView and provides the child view for it. Android allows you to create custom adaptor for your application by extending class with BaseAdapter.

Android also provides a set of build-in adapter classes that can be used for different purposes e.g

  1. ArrayAdapter
  2. CursorAdapter
  3. SimpleAdapter
  4. SimpleCursorAdapter

Array Adapter

ArrayAdapter is the simplest adapter available in Android, it takes array and convert items into the view object. By default it binds the toString() value of the object to TextView.

This image is very good for understanding the ArrayAdapter. On the left hand side there is AdapterView, in this image we have ListView and it is displaying each element in TextView. On right side of the image we have list of items. Map the list view and items using the ArrayAdapter. ArrayAdapter maps the each item using layout R.layout.childView.

For proper understanding of the Adapter add the EditText and ListView control in the layout file.

 <relativelayout 
        xmlns:android="http://schemas.android.com/apk/res/android" 
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent" 
        android:layout_height="match_parent" 
        tools:context=".MainActivity">
    <LinearLayout
        android:id="@+id/topBar"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
       android:background="#e1e1e1"
        android:padding="10dp">
  
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Add Text:"/>
  
        <EditText
            android:text=""
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:id="@+id/txtAddNew" 
            android:singleLine="true"/>
  
    </LinearLayout>
    <ListView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/listView"
        android:layout_below="@+id/topBar"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"/>
</relativelayout>
    

In the code file declare variable of ArrayAdapter<String>, which means ArrayAdapter will contain list of string as data items. The ArrayAdapter takes 3 parameters in constructor. Context, Layout id and list of data. After creating the instance of ArrayAdapter assign it to the ListView using setAdapter() method of ListView. See the code below.

 ArrayAdapter<String> _adapter ;
 ArrayList<String> _items;
 ListView _listView;
 private void BindList() {
    _items = new ArrayList<String>();
    for (int i = 1; i <= 10; i++) {
        _items.add("Item : " + i);
    }
    int layoutId = android.R.layout.simple_list_item_1;
    _adapter = new ArrayAdapter<String>(this, layoutId, _items);
    _listView = (ListView) findViewById(R.id.listView);
    _listView.setAdapter(_adapter);
 }

For creating the instance of the ArrayAdapter, Prepare the List<String> and using default android layout android.R.layout.simple_list_item_1 for displaying data in TextView. Create the instance of the ArrayAdapter using statement _adapter = new ArrayAdapter<String>(this, layoutId, _items); where _items is the list of data

Find the ListView in layout and set adapter using _listView.setAdapter(_adapter); statement.

User can also add data into the Adapter. Register the Key Listener for the EditText. And on press of Enter key add data into the Adapter.

 private void RegisterkeyEventForTxtAdd()
 {
    final TextView txtAddNew = (TextView)findViewById(R.id.txtAddNew);
    txtAddNew.setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
            if (keyEvent.getAction() == KeyEvent.ACTION_DOWN)
                if (keyCode == KeyEvent.KEYCODE_ENTER) {
                    String newItem;
                    newItem = txtAddNew.getText().toString();
                    _items.add(0, newItem);
                    txtAddNew.setText("");
                    _adapter.notifyDataSetChanged();
                    return true;
                }
            return false;
        }
    });
 }
 

Add the newly entered text in to the _items list using _items.add(0, newItem) Statement. And then call the notifyDataSetChanged() method of the adapter.

Run the application and it will show the option to add new item in list.

Custom Array Adapter:

For customizing layout design for list view item extend the adapter class and override its methods. For example each item of the adapter view should show Name and Joining Date.

Create a layout file for item and name it “user_list_layout.xml” and add TextView for Name and Date.

Following is the xml of layout file.

    
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="4dp" >
    <TextView
        android:id="@+id/txtName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Name" />
    <TextView
        android:id="@+id/txtDate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#a1a1a1"
        android:textSize="10dp"
        android:text="Date" />
 </LinearLayout>

Create a new class UserInfo and add fields name and joining date in it.

 public class UserInfo {

    String _name;
    Date _joiningDate;

    public UserInfo(){}

    public UserInfo(String name, Date joiningDate)
    {
        _name = name;
        _joiningDate = joiningDate;
    }

    public void setName(String name){_name=name;}

    public String getName(){return _name;}

    public void setJoiningDate(Date joiningDate){_joiningDate=joiningDate;}
    
    public Date getJoiningDate(){return _joiningDate;}

 }

For creating custom adapter create a class UserArrayAdapter and extend it with ArrayAdapter<UserInfo> class and override getView() method. See the code below

 
 public class UserArrayAdapter extends ArrayAdapter<UserInfo> {

    private Context _context;
    int _layoutId;

    public UserArrayAdapter(Context context,
                            int layoutId,
                            List<UserInfo> items) {
        super(context, layoutId, items);
        _context = context;
        _layoutId = layoutId;
    }

    @Override
    public View getView(int position, View view, ViewGroup parent) {
        
        UserInfo item = getItem(position);
        
        String name = item.getName();
        Date joiningDate = item.getJoiningDate();
        SimpleDateFormat dateFormatter = new SimpleDateFormat("dd/MM/yy");
        String dateString = dateFormatter.format(joiningDate);
        
        if (view == null) {
            LayoutInflater inflater = (LayoutInflater)_context.
                                       getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(_layoutId, parent,false);
        }
        
        TextView nameView = (TextView)view.findViewById(R.id.txtName);
        TextView dateView = (TextView)view.findViewById(R.id.txtDate);
        
        nameView.setText(name);
        dateView.setText(dateString);
        
        return view;
    }

 }
 

In the constructor of the class pass the context, layout Id and list of items. Pass these parameters to the base class using super(context, layoutId, items); statement.

The getView() method calls for each list item. Position indicates the index of the item. Get the data item for that position using UserInfo item = getItem(position); statement. If view is currently not generated for item and is null then create it using layout inflater

 if (view == null) {
    LayoutInflater inflater = (LayoutInflater)_context.getSystemService(
                                                Context.LAYOUT_INFLATER_SERVICE);
    view = inflater.inflate(_layoutId, parent,false);
 }

Once view layout is inflated find the controls from layout and assign the values accordingly.

 TextView nameView = (TextView)view.findViewById(R.id.txtName);
 TextView dateView = (TextView)view.findViewById(R.id.txtDate);
 
 nameView.setText(name);
 dateView.setText(dateString);
    

Now custom adapter is ready to use. Create new activity and add ListView control in the Layout file. In the activity code file write the code to bind ListView with custom adapter.

 List<userinfo> _items;
   
 private void BindList() {
    _items = new ArrayList<userinfo>();
 
   for (int i = 1; i <= 10; i++) {
        String name = "User " + i;
        Date date = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, -i);
        date = calendar.getTime();
        _items.add(new UserInfo(name,date));
    }
 
   int layoutId = R.layout.user_list_layout;
    UserArrayAdapter adapter = new UserArrayAdapter(this, layoutId, _items);
    ListView listView = (ListView) findViewById(R.id.listView);
    listView.setAdapter(adapter);
 }

Create an instance of ArrayList<userinfo> class and add UserInfo class items in it. Get your custom layout id using R.layout.user_list_layout. Create the instance of UserArrayAdapter class and pass context, layoutId and list of item as parameters in constructor.



Simple Cursor Adapter:

The SimpleCursorAdapter allows to bind columns from a database cursor to an Adapter View using a custom layout definition. The simple cursor adapter takes context, layout id, cursor and two arrays. First array contains the name of columns to be used in cursor and second array contains the ids of the views/controls in the layout for column’s name provided in first array.

The simple cursor adapter converts a row from the cursor to child view of the AdapterView. For more understanding how this adapter works. Create an application and show contacts in the List View.

Create the layout for single item and name it simple_cursor_layout and add two TextView in it, one for Name and other of id.

 
 <?xml version="1.0" encoding="utf-8" ?>
 <linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical" android:layout_width="match_parent"
              android:layout_height="match_parent">
        
        <textview android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:textappearance="?android:attr/textAppearanceLarge"
                  android:text="Large Text"
                  android:id="@+id/textViewName" />
        
        <textview android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:textappearance="?android:attr/textAppearanceSmall"
                  android:text="Small Text"
                  android:id="@+id/textViewNumber" />
 
 </linearlayout>

Create new activity and name it simpleCursorActivity and add ListView Control in the Layout file

<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context="org.brainysolutions.myadapter.SimpleCursorAcitivy">
    
    <listview android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:id="@+id/listView"
            android:layout_alignparentright="true"
            android:layout_alignparentend="true" />

</relativelayout>

In the code file create a Cursor using managedQuery and pass the required parameters to it. Create an array of column names that you want to fetch from cursor and array for the ids of the Views/Controls in layout to show data of fetched columns. The sequence of column name and corresponding fields should be same in two arrays.

Create the instance of SimpleCursorAdapter class and pass the context, layout id, columns name and views as parameter in constructor.

 ListView listView = (ListView) findViewById(R.id.listView);

 Cursor c = managedQuery(ContactsContract.Contacts.CONTENT_URI,
                        null, null, null, ContactsContract.Contacts.DISPLAY_NAME + " ASC");

 String[] cols =  new String[] {ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts._ID};
 int[] views = new int[] { R.id.textViewName, R.id.textViewNumber};
 
 SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
    R.layout.simple_cursor_layout,
    c, cols, views);
 
 listView.setAdapter(adapter);

You will also need to have permission to read contacts. Open the AndroidManifest.xml file and add the uses-permission tags to get the read contact permission.

 <uses-permission android:name="android.permission.READ_CONTACTS" />

Run the application and it will show the contact's display name and id in the list view. If contacts are not available then it will show empty list. You can also add contact if you are using emulator.

Download Source Code

You can get the source code. Download Source Code

;