Lesson 53. SimpleCursorTreeAdapter, use case

Lesson 53. SimpleCursorTreeAdapter, use case

In this lesson:

– we use SimpleCursorTreeAdapter to build the list

The SimpleCursorTreeAdapter is not a complete ready-made adapter. This is an abstract class, it requires the implementation of the Cursor method getChildrenCursor (Cursor groupCursor).

What is the method and what do you need to write in it to make it work? To understand this, we need to understand the algorithm of this adapter, let’s consider one of the constructors: SimpleCursorTreeAdapter (Context context, Cursor cursor, int groupLayout, String[] groupFrom, int[] groupTo, int childLayout, String[] childFrom, int[] childTo).

We specify in the constructor cursor is a group cursor. It contains data on groupsYou need to list the data. That is all as in use SimpleCursorAdapter (See Previous Lessons). And the adapter quietly displays collapsed groups using data from this cursor. When comparing cursor fields and View components, it uses arrays groupFrom[] and groupTo[].

But if we want to expand the group and look elements, Then the adapter is nowhere to take the data by element. cursor cursor contains data only on groups. In this case, the adapter puts in cursor the position corresponding to the information disclosed to the group invokes the method getChildrenCursor, Forwards this group cursor to him and waits for a response cursor elements of this group.

In the implementation of this method, we get the id of the current information, which is revealed by the group from the cursor groups, we query it in the database and receive in the form of the cursor data on to the elements groups. We return this element cursor as result method getChildrenCursor and the adapter uses it to create group elements. Arrays are used to map cursor fields and View components childFrom and childTo.

Well, let’s see what else is left in the constructor:
context – context
groupLayout – layout resource for group display
childLayout – layout resource for displaying an element

In general, everything is easy, consider the example. Let’s make a list of companies (groups) and their smartphones (items).


Let’s create a project:

Project name: P0531_SimpleCursorTreeAdapter
Build Target: Android 2.3.3
Application name: SimpleCursorTreeAdapter
Package name: ru.startandroid.develop.p0531simplecursortreeadapter
Create Activity: MainActivity

screen main.xml:


Since we will need a database, we will allocate a separate class to work with it


package ru.startandroid.develop.p0531simplecursortreeadapter;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;

public class DB {

  private static final String DB_NAME = "mydb";
  private static final int DB_VERSION = 1;

  // имя таблицы компаний, поля и запрос создания 
  private static final String COMPANY_TABLE = "company";
  public static final String COMPANY_COLUMN_ID = "_id";
  public static final String COMPANY_COLUMN_NAME = "name";
  private static final String COMPANY_TABLE_CREATE = "create table "
      + " integer primary key, " + COMPANY_COLUMN_NAME + " text" + ");";
  // имя таблицы телефонов, поля и запрос создания
  private static final String PHONE_TABLE = "phone";
  public static final String PHONE_COLUMN_ID = "_id";
  public static final String PHONE_COLUMN_NAME = "name";
  public static final String PHONE_COLUMN_COMPANY = "company";
  private static final String PHONE_TABLE_CREATE = "create table "
      + " integer primary key autoincrement, " + PHONE_COLUMN_NAME
      + " text, " + PHONE_COLUMN_COMPANY + " integer" + ");";

  private final Context mCtx;

  private DBHelper mDBHelper;
  private SQLiteDatabase mDB;

  public DB(Context ctx) {
    mCtx = ctx;

  // открываем подключение
  public void open() {
    mDBHelper = new DBHelper(mCtx, DB_NAME, null, DB_VERSION);
    mDB = mDBHelper.getWritableDatabase();

  // закрываем подключение
  public void close() {
    if (mDBHelper != null)

  // данные по компаниям
  public Cursor getCompanyData() {
    return mDB.query(COMPANY_TABLE, null, null, null, null, null, null);

  // данные по телефонам конкретной группы
  public Cursor getPhoneData(long companyID) {
    return mDB.query(PHONE_TABLE, null, PHONE_COLUMN_COMPANY + " = "
        + companyID, null, null, null, null);

  private class DBHelper extends SQLiteOpenHelper {

    public DBHelper(Context context, String name, CursorFactory factory,
        int version) {
      super(context, name, factory, version);

    public void onCreate(SQLiteDatabase db) {
      ContentValues cv = new ContentValues();

      // названия компаний (групп)
      String[] companies = new String[] { "HTC", "Samsung", "LG" };
      // создаем и заполняем таблицу компаний
      for (int i = 0; i < companies.length; i++) {
        cv.put(COMPANY_COLUMN_ID, i + 1);
        cv.put(COMPANY_COLUMN_NAME, companies[i]);
        db.insert(COMPANY_TABLE, null, cv);

      // названия телефонов (элементов)
      String[] phonesHTC = new String[] { "Sensation", "Desire",
          "Wildfire", "Hero" };
      String[] phonesSams = new String[] { "Galaxy S II", "Galaxy Nexus",
          "Wave" };
      String[] phonesLG = new String[] { "Optimus", "Optimus Link",
          "Optimus Black", "Optimus One" };

      // создаем и заполняем таблицу телефонов
      for (int i = 0; i < phonesHTC.length; i++) {
        cv.put(PHONE_COLUMN_COMPANY, 1);
        cv.put(PHONE_COLUMN_NAME, phonesHTC[i]);
        db.insert(PHONE_TABLE, null, cv);
      for (int i = 0; i < phonesSams.length; i++) {
        cv.put(PHONE_COLUMN_COMPANY, 2);
        cv.put(PHONE_COLUMN_NAME, phonesSams[i]);
        db.insert(PHONE_TABLE, null, cv);
      for (int i = 0; i < phonesLG.length; i++) {
        cv.put(PHONE_COLUMN_COMPANY, 3);
        cv.put(PHONE_COLUMN_NAME, phonesLG[i]);
        db.insert(PHONE_TABLE, null, cv);

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {


We create two tables: company (Companies) and phone (Phones). In the table of phones we indicate for each phone his group id from the business table. We also create methods for opening and closing connections, and methods for obtaining data by group and by elements of a particular group.

code MainActivity.java:

package ru.startandroid.develop.p0531simplecursortreeadapter;

import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.widget.ExpandableListView;
import android.widget.SimpleCursorTreeAdapter;

public class MainActivity extends Activity {

  ExpandableListView elvMain;
  DB db;

  /** Called when the activity is first created. */
  public void onCreate(Bundle savedInstanceState) {

    // подключаемся к БД
    db = new DB(this);

    // готовим данные по группам для адаптера
    Cursor cursor = db.getCompanyData();
    // сопоставление данных и View для групп
    String[] groupFrom = { DB.COMPANY_COLUMN_NAME };
    int[] groupTo = { android.R.id.text1 };
    // сопоставление данных и View для элементов
    String[] childFrom = { DB.PHONE_COLUMN_NAME };
    int[] childTo = { android.R.id.text1 };

    // создаем адаптер и настраиваем список
    SimpleCursorTreeAdapter sctAdapter = new MyAdapter(this, cursor,
        android.R.layout.simple_expandable_list_item_1, groupFrom,
        groupTo, android.R.layout.simple_list_item_1, childFrom,
    elvMain = (ExpandableListView) findViewById(R.id.elvMain);

  protected void onDestroy() {

  class MyAdapter extends SimpleCursorTreeAdapter {

    public MyAdapter(Context context, Cursor cursor, int groupLayout,
        String[] groupFrom, int[] groupTo, int childLayout,
        String[] childFrom, int[] childTo) {
      super(context, cursor, groupLayout, groupFrom, groupTo,
          childLayout, childFrom, childTo);

    protected Cursor getChildrenCursor(Cursor groupCursor) {
      // получаем курсор по элементам для конкретной группы
      int idColumn = groupCursor.getColumnIndex(DB.COMPANY_COLUMN_ID);
      return db.getPhoneData(groupCursor.getInt(idColumn));

IN onCreate we connect to the database, create an adapter and a list.

IN onDestroy close the connection.

class MyAdapter - implementation of abstract SimpleCursorTreeAdapter. We use the constructor by default. In the method getChildrenCursor we get the id of the current group and get a cursor on it with the data about the group elements.

We save everything, run it.

The list tree works.

If you hang group and element click handlers on the list, they will not only give you the item position in the list, but also the corresponding _id value from the database.

comparison data and View-component is the same as for SimpleCursorAdapter. If there is an external ViewBinder, its setViewValue method is called. If not, there is standard processing for TextView and ImageView. Binding details can be found in past lessons.

In the next lesson:

- we create our adapter based on BaseAdapter

Discuss in the forum [91 replies]
Related Posts
Lesson 190. Notifications. channels

Android Oreo (API 26) has the ability to create message channels. In this lesson we will understand how to Read more

Lesson 189. Notifications. message grouping

Android 7 (API 24) has the ability to group messages. Even if you don't explicitly implement it, the system Read more

Lesson 188. Notifications. custom messages

Android enables us to create a layout for messages ourselves. Consider a simple example: layout / notification.xml Height 64dp Read more

Lesson 187. Notifications. Action buttons. Reply.

Android 4.1 has the ability to add buttons to messages. This is done using the addAction method. Intent deleteIntent Read more

Leave a Comment