IT練習ノート

IT関連で調べたこと(実際は嵌ったこと)を書いています。

SQLiteのカーソルをうまいこと使えないものかと思った件

実際はCotentProvider経由だと思うので、あんまりやることはないと思いますが、試してみました。

CursorにDataSetObserverがあり、対象のデータを更新したら、いい感じに通知があるのかなと思ったのですが、それほどいい感じのようには思えませんでした。

処理の流れは次のようになります。

cursor取得 
  -> データ更新
      -> 明示的にrequeryを呼ぶ
         -> DataSetObserver経由でonChangedメソッドが呼び出される。

下記コードではやってませんが、Activityのライフサイクルを考慮した場合、cursorを保持し続けるのはどうなんでしょうか?

public class MainActivity extends ActionBarActivity {

    private TextView textView;
    private Button btnSelect;
    private Button btnInsert;
    private SQLiteDatabase db;
    // カーソルを保持しておくため
    private SQLiteCursor cursor;

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnSelect = (Button)findViewById(R.id.btnSelect);
        btnInsert = (Button)findViewById(R.id.btnInsert);
        textView = (TextView)findViewById(R.id.text);

        MyDBHelper helper = new MyDBHelper(this.getApplicationContext(), "mydb", null, 1);
        db = helper.getWritableDatabase();

        cursor = (SQLiteCursor)db.rawQuery("select id, name, tel, address from people", null, null);
        cursor.registerDataSetObserver(new DataSetObserver() {
            @Override
            public void onChanged() {
                // このメソッドのパラメータはなし
                super.onChanged();
                updateTextView();
            }
        });

        // テーブルの内容表示
        btnSelect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                updateTextView();
            }
        });

        // テーブルにデータを登録する
        btnInsert.setOnClickListener(new View.OnClickListener() {
            @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
            @Override
            public void onClick(View view) {

//                カーソルを保持するなら件数が数えられるので、idを取り直さなくても良いかも(idがずれない前提であれば)
//                cursor.getCount()
//                Cursor c1 = db.rawQuery("select max(id) from people", null, null);
//                c1.moveToFirst();
//                int max = c1.getInt(0);

                db.beginTransaction();
                String name = getTextVal(R.id.editName);
                String tel = getTextVal(R.id.editTel);
                String address = getTextVal(R.id.editAddress);

                db.execSQL("insert into people (id, name, tel, address) values (?, ?, ?, ?)",
                        new Object[]{cursor.getCount() + 1, name, tel, address});

//                更新のケースも対応する場合は、replaceを使った方が楽なはず。
//                ContentValues cv = new ContentValues();
//                cv.put("id", cursor.getCount() + 1);
//                cv.put("name", name);
//                cv.put("tel", tel);
//                cv.put("address", address);
//                db.replace("people", null, cv);

                db.setTransactionSuccessful();
                db.endTransaction();

                // これの使いどころとしてどんなもんだろうか?
                cursor.requery();

            }
        });

    }

    private String getTextVal(int resId) {
        return ((EditText)findViewById(resId)).getText().toString();
    }

    private void updateTextView() {
        textView.setText("");
        cursor.moveToFirst();
        do {
            int id = cursor.getInt(0);
            String name = cursor.getString(1);
            String tel = cursor.getString(2);
            String address = cursor.getString(3);
            textView.append(id + "," + name + ", " + tel + "," + address
                    + System.getProperty("line.separator"));
            // 便利なメソッドがあった
            // 下記のような感じでログがだせる
            // このメソッドを読んでもカーソル位置は変わらない。
//            05-04 20:54:58.785    9033-9033/com.example.test02 D/test02﹕ 0 {
//                id=1
//                name=satoshi
//                tel=090-0000-0001
//                address=tokyo
//            }
            Log.d("test01", DatabaseUtils.dumpCurrentRowToString(cursor));
        } while (cursor.moveToNext());
    }

    @Override
    protected void onDestroy() {
        if (cursor != null) {
            cursor.close();
        }
        if (db != null) {
            db.close();
        }
        super.onDestroy();
    }

...
}