Como Exibir Dados do SQLite no ExpandableList

Na documentação do Android existem alguns exemplos de utilização do ExpandableList que é similar ao ListView, com a diferença que o ExpandableList exibe uma lista que pode ser expandida em dois níveis. Os dados que são exibidos no ExpandableList podem ser fornecidos de várias fontes, como por exemplo arrays.

Este post vai utilizar como fonte de dados, para preencher o ExpandableList, uma base de dados SQLite, e para isso utiliza como base o mesmo projeto do post SQLite em Aplicações Android, que possui uma base de dados de livros armazenados em uma base SQLite. Esta versão exibe uma tela com o título do livro em um nível e o nome do autor, ano e genêro do livro em outro nível do ExpandableList.

device-2012-12-19-173925

Para exibir as informações do livro no ExpandableList é necessário inserir no projeto uma classe para exibir o ExpandableList (classe ExpandableActivity), um arquivo de layout para as informações que são exibidas no segundo nível (expandable_child.xml),  e uma classe Adapter (LivroAdapter) para expor os dados do livro no ExpandableList.

A classe ExpandableList herda da classe ExpandableListActivity e configura o Adapter que é utilizado para exibir as informações dos livros.

public class ExpandableActivity extends ExpandableListActivity {
    private LivroDb livroDb;
    
   @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        livroDb = new LivroDb(this);
        
        LivroAdapter livroAdapter = new LivroAdapter(livroDb.getCursor(),
                this);
        setListAdapter(livroAdapter);
   }
    
   @Override
   protected void onDestroy() {
        super.onDestroy();     
        // Fecha a base de dados
        livroDb.close();
   }
}


O layout para exibir os dados do segundo nível do ExpandableList pode ser customizado, neste caso foram utilizados somente TextView.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <TextView 
        android:id="@+id/textAutor"
        android:layout_width="match_parent"
        android:layout_height="40dp"
     />

     <TextView 
        android:id="@+id/textAno"
        android:layout_width="match_parent"
        android:layout_height="40dp"
     />
        
    <TextView 
        android:id="@+id/textGenero"
        android:layout_width="match_parent"
        android:layout_height="40dp"
     />
</LinearLayout>

A classe LivroAdapter herda da classe CursorTreeAdapter que expõe dados utilizando um Cursor. Esta classe utiliza o Cursor fornecido pelo SQLite e os métodos que devem ser implementados são:

public class LivroAdapter extends CursorTreeAdapter {
      LayoutInflater layoutInflater;
      
      public LivroAdapter(Cursor cursor, Context context) {
            super(cursor, context);
            layoutInflater = LayoutInflater.from(context);
      }
 
      // Exibe as informações do segundo nível.
      @Override
      protected void bindChildView(View view, Context context, Cursor cursor,
                  boolean isLastChild) {
              TextView textAutor = (TextView)view.findViewById(R.id.textAutor);
              textAutor.setText(cursor.getString(cursor.getColumnIndex("autor")));
              TextView textAno = (TextView)view.findViewById(R.id.textAno);
              textAno.setText(cursor.getString(cursor.getColumnIndex("ano_publicacao")));
              TextView textGenero = (TextView)view.findViewById(R.id.textGenero);
              textGenero.setText(cursor.getString(cursor.getColumnIndex("genero")));              
      }
 
      // Exibe as informações do primeiro nível.
      @Override
      protected void bindGroupView(View view, Context context, Cursor cursor,
                  boolean isExpanded) {
            TextView textTitulo = (TextView)view.findViewById(android.R.id.text1);
            textTitulo.setText(cursor.getString(cursor.getColumnIndex("titulo")));
      }
 
      // Lê o Cursor da base SQLite.
      @Override
      protected Cursor getChildrenCursor(Cursor groupCursor) {
            int id = groupCursor.getInt(groupCursor.getColumnIndex("_id"));
            return Principal.livros.getCursorById(id);
      }
 
      // Monta o layout do segundo nível.
      @Override
      protected View newChildView(Context context, Cursor cursor,
                  boolean isLastChild, ViewGroup parent) {
              View view = layoutInflater.inflate(
                R.layout.expandable_child, null);
              TextView textAutor = (TextView)view.findViewById(R.id.textAutor);
              textAutor.setText(cursor.getString(cursor.getColumnIndex("autor")));
              TextView textAno = (TextView)view.findViewById(R.id.textAno);
              textAno.setText(cursor.getString(cursor.getColumnIndex("ano_publicacao")));
              TextView textGenero = (TextView)view.findViewById(R.id.textGenero);
              textGenero.setText(cursor.getString(cursor.getColumnIndex("genero")));              
              
            return view;
      }
 
      // Monta o layout do primeiro nível.
      @Override
      protected View newGroupView(Context context, Cursor cursor,
                  boolean isExpanded, ViewGroup parent) {
            View view = layoutInflater.inflate(
                        android.R.layout.simple_expandable_list_item_1, null);
            TextView textTitulo = (TextView)view.findViewById(android.R.id.text1);
            textTitulo.setText(cursor.getString(cursor.getColumnIndex("titulo")));
            return view;
      }
 
}

As informações dos livros são exibidas no ExpandableList da seguinte forma:
imagem

O código fonte do projeto pode ser obtido no link Download do Projeto.

O emulador Android utilizado foi configurado com a API 15 (Android 4.0.3 Ice Cream Sandwich).