Lesson 52. SimpleCursorAdapter, use case

Lesson 52. SimpleCursorAdapter, use case


In this lesson:

– we use SimpleCursorAdapter to build the list
– add and delete entries in the list

Important note! The lesson is no longer relevant because it uses methods that Google has declared obsolete. If you just went to see how to use SimpleCursorAdapter, then instead of this lesson, I recommend you to read Lesson 136. If you go through the lessons consistently, you can read and understand this lesson, and then simply acclimatize your knowledge in Lesson 136.

After a few lessons devoted SimpleAdapter we know enough about him and outline his work. And now it will be easy for us to learn SimpleCursorAdapter. It differs in that the data used is not the Map collection, but Cursor with data from the database. And in the array from, respectively, we did not specify the keys of Map-attributes, but the name of the fields (column) of the cursor. The values ​​from these fields will be mapped to the specified View components from the array.

Also a bit different from the SimpleAdapter standard Binding and external ViewBinder. SimpleCursorAdapter is able to work with TextView and ImageView components and their derivatives, and will not accept Checkable derivatives. And when using ViewBinder, it is necessary to implement its method boolean setViewValue (View view, Cursor cursor, int columnIndex). He accepts the entrance View– component for Binding, cursor with data and column numberFrom which to get the data. The cursor position is already set according to the position of the list item. I will not post again the use cases, because they will be very similar to the examples from the previous SimpleAdapter lessons. If everything was clear, then there should not be any problems.

So, let’s give an example of use SimpleCursorAdapter. The list will display the picture and the text. We also realize the opportunity addition and removal data from the list. We will add a button and delete it using the context menu.

Let’s create a project:

Project name: P0521_SimpleCursorAdapter
Build Target: Android 2.3.3
Application name: SimpleCursorAdapter
Package name: ru.startandroid.develop.p0521simplecursoradapter
Create Activity: MainActivity

Typically, in the lessons, I used to text the buttons and more directly. I did it not out of harm’s way, but not to overload the lesson with extra information. But with the latest updates, Eclipse has become something like this: [I18N] Hardcoded string “some text”, should use @string resource. The error is not critical and the launch of the application does not hurt, but some it confuses. And really, hardcode is bad. In this lesson, I will try to follow the rules of good tone and use the files resources. At our current level of knowledge, this should not be an obstacle to understanding and learning lessons.

fill in res / values ​​/ string.xml:



    SimpleCursorAdapter
    Добавить запись
    Удалить запись

Here, in addition to the name of the program, I wrote down the texts for the button and the context menu

screen main.xml:



    
    
    

Button to add record and list.

Layout for a list item item.xml:



    
    
    
    

Picture and text.

Because SimpleCursorAdapter is a data adapter with DB, Then we need to organize this database. Not to clutter up MainActivity.java, I will pass the code on work with a DB in a separate class DB. we create a class DB.java in the same package as MainActivity.java

code DB.java:

package ru.startandroid.develop.p0521simplecursoradapter;

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 DB_TABLE = "mytab";
  
  public static final String COLUMN_ID = "_id";
  public static final String COLUMN_IMG = "img";
  public static final String COLUMN_TXT = "txt";
  
  private static final String DB_CREATE = 
    "create table " + DB_TABLE + "(" +
      COLUMN_ID + " integer primary key autoincrement, " +
      COLUMN_IMG + " integer, " +
      COLUMN_TXT + " text" +
    ");";
  
  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) mDBHelper.close();
  }
  
  // получить все данные из таблицы DB_TABLE
  public Cursor getAllData() {
    return mDB.query(DB_TABLE, null, null, null, null, null, null);
  }
  
  // добавить запись в DB_TABLE
  public void addRec(String txt, int img) {
    ContentValues cv = new ContentValues();
    cv.put(COLUMN_TXT, txt);
    cv.put(COLUMN_IMG, img);
    mDB.insert(DB_TABLE, null, cv);
  }
  
  // удалить запись из DB_TABLE
  public void delRec(long id) {
    mDB.delete(DB_TABLE, COLUMN_ID + " = " + id, null);
  }
  
  // класс по созданию и управлению БД
  private class DBHelper extends SQLiteOpenHelper {

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

    // создаем и заполняем БД
    @Override
    public void onCreate(SQLiteDatabase db) {
      db.execSQL(DB_CREATE);
      
      ContentValues cv = new ContentValues();
      for (int i = 1; i < 5; i++) {
        cv.put(COLUMN_TXT, "sometext " + i);
        cv.put(COLUMN_IMG, R.drawable.ic_launcher);
        db.insert(DB_TABLE, null, cv);
      }
    }

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

Here we are all familiar with the past lessons SQLite.

We create several public methods so that Activity can use them to work with data:

open - to establish a connection
close - close the connection
getAllData - Get a cursor with all the data in the table
addRec - Add entry
delRec - delete the entry

These are shell methods for working with a database that will give MainActivity only the capabilities it needs.

nested class DBHelper - to create and manage a database. In the method onCreate we create a table and populate it and generate data. method onUpgrade I left blank because in this example I do not plan to update the database version.

code MainActivity.java:

package ru.startandroid.develop.p0521simplecursoradapter;

import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;

public class MainActivity extends Activity {

  private static final int CM_DELETE_ID = 1;
  ListView lvData;
  DB db;
  SimpleCursorAdapter scAdapter;
  Cursor cursor;

  /** Called when the activity is first created. */
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // открываем подключение к БД
    db = new DB(this);
    db.open();

    // получаем курсор
    cursor = db.getAllData();
    startManagingCursor(cursor);
    
    // формируем столбцы сопоставления
    String[] from = new String[] { DB.COLUMN_IMG, DB.COLUMN_TXT };
    int[] to = new int[] { R.id.ivImg, R.id.tvText };

    // создааем адаптер и настраиваем список
    scAdapter = new SimpleCursorAdapter(this, R.layout.item, cursor, from, to);
    lvData = (ListView) findViewById(R.id.lvData);
    lvData.setAdapter(scAdapter);

    // добавляем контекстное меню к списку
    registerForContextMenu(lvData);
  }

  // обработка нажатия кнопки
  public void onButtonClick(View view) {
    // добавляем запись
    db.addRec("sometext " + (cursor.getCount() + 1), R.drawable.ic_launcher);
    // обновляем курсор
    cursor.requery();
  }

  public void onCreateContextMenu(ContextMenu menu, View v,
      ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);
    menu.add(0, CM_DELETE_ID, 0, R.string.delete_record);
  }
  
  public boolean onContextItemSelected(MenuItem item) {
    if (item.getItemId() == CM_DELETE_ID) {
      // получаем из пункта контекстного меню данные по пункту списка 
      AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) item.getMenuInfo();
      // извлекаем id записи и удаляем соответствующую запись в БД
      db.delRec(acmi.id);
      // обновляем курсор
      cursor.requery();
      return true;
    }
    return super.onContextItemSelected(item);
  }
  
  protected void onDestroy() {
    super.onDestroy();
    // закрываем подключение при выходе
    db.close();
  }

}

Good thing we created DB.java. Thanks to it in MainActivity.java everything is beautiful, transparent and convenient. We look at the code.

IN onCreate we organize the connection to the database, get the cursor and ask Activity to look after it. Now when you change the Activity Lifecycle states, it will change the cursor state accordingly. Then we configure Binding - we form arrays that will specify the adapter, how to compare the data from the cursor and View components. In R.id.ivImg the value from the img field will go, and in R.id.tvText the value from the txt field. Field names are specified here by public constants of the DB class. Next, we create an adapter and set up a list to use it. Finally, we add a context menu to the list.

In the method onButtonClick we generate and add a record to the database and update the cursor with the requery method to get fresh data from the database.

When creating a context menu, in method onCreateContextMenu, We add an item to remove.

In the method onContextItemSelected we handle clicking the context menu item. We use getMenuInfo method to get information on a list item for which the context menu was called. object AdapterContextMenuInfo contains View, id, and list item positions. We need id. this id is equal to the value of the field _id for the corresponding cursor entry. We call the record deletion method and update the cursor.

In the method onDestroy we close the database connection. This will happen when the Activity closes.

We save and run everything.

At the push of a button, we add an entry. And by clicking the context menu (click) for a list item, you can delete it.

We have considered adding and deleting entries in the list when using SimpleCursorAdapter. I did not consider editing. This would not make the lesson particularly difficult, but it would make it more difficult and blur the subject. And I try to make the lessons as sharp as possible for a specific topic. For those who are interested in editing, Google has kindly created this example on the official site - http://developer.android.com/resources/tutorials/notepad/index.html. My example is similar to it, so it will be easier to understand.

By the way, in this lesson we came across a list where the id of the item might not match the position. For the test, try to hang the list item's processing and see that the position is the position of the item in the list and the id is the database record identifier (_id field). For this to work, you need to call the ID field in the table _id, because the cursor will use it as an id. Otherwise we will get an error.

In the next lesson:

- we use SimpleCursorTreeAdapter to build the list




Discuss in the forum [370 replies]

Leave a Comment