昨日の失態

ContentProvider を継承したソレをスルーで自動でなんとかなるなんて凄いな、という大ナチュラルをぶちカマしてしまった事によります。とりあえず MyTracks の MyTracksProvider を参考にして簡易版をでっち上げてみます。

必要と思われるもの

  • SQLiteOpenHelper を継承した内部クラス
  • onCreate メソド
  • delete メソド
  • getType メソド
  • insert メソド
  • query メソド
  • update メソド

Notepad Tutorial なソレはテーブル単発なので、省略して書いちゃえ。

DatabaseHelper

まずこれから。

  private static class DatabaseHelper extends SQLiteOpenHelper {

    public DatabaseHelper(Context context) {
      super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
      db.execSQL(DATABASE_CREATE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
      Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
          + newVersion + ", which will destroy all old data");
      db.execSQL("DROP TABLE IF EXISTS notes");
      onCreate(db);
    }
  }

このあたりは NotesDBAdapter なナニの記述に添えば OK か。onCreate も同じで良いはず。

  @Override
  public boolean onCreate() {
    DatabaseHelper dbHelper = new DatabaseHelper(getContext());
    db = dbHelper.getWritableDatabase();
    return db != null;
  }

delete は以下かな。

  @Override
  public int delete(Uri url, String where, String[] selectionArgs) {
    int count = db.delete("notes", where, selectionArgs);
    getContext().getContentResolver().notifyChange(url, null, true);
    return count;
  }

次は getType はケツがレコード番号かどうかを判定しないといけない模様。なのでコンストラクタでマッチャの仕込みをしておく必要がある模様。コンストラクタが以下?

  public NotepadProvider() {
    urlMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    urlMatcher.addURI("com.android.demo.notepad3", "notes", NOTES);
    urlMatcher.addURI("com.android.demo.notepad3", "notes/#", NOTES_ID);
  }

UriMatcher のフォローが必要か。あと以下な属性の定義も必要かな。

  private static final int NOTES = 1;
  private static final int NOTES_ID = 2;

で、以下が gettype メソド。

  @Override
  public String getType(Uri url) {
    switch (urlMatcher.match(url)) {
      case NOTES:
        return "vnd.android.cursor.dir/vnd.google.track";
      case NOTES_ID:
        return "vnd.android.cursor.item/vnd.google.track";
      default:
        throw new IllegalArgumentException("Unknown URL " + url);
    }
  }

google になってるけどスルー、って事で。。
以降続けて以下。

  @Override
  public Uri insert(Uri url, ContentValues initialValues) {
    ContentValues values;
    if (initialValues != null) {
      values = initialValues;
    } else {
      values = new ContentValues();
    }
    long rowId = db.insert(DATABASE_TABLE, null, values);
    if (rowId >= 0) {
      Uri uri = ContentUris.appendId(NotesDBAdapter.CONTENT_URI.buildUpon(), rowId).build();
      getContext().getContentResolver().notifyChange(url, null, true);
      return uri;
    }
    throw new SQLiteException("Failed to insert row into " + url);
  }

  @Override
  public Cursor query(
      Uri url, String[] projection, String selection, String[] selectionArgs,
      String sort) {
    SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
    String sortOrder = null;
    qb.setTables("notes");
    qb.appendWhere("_id=" + url.getPathSegments().get(1));

    Cursor c = qb.query(db, projection, selection, selectionArgs, null, null,
        sortOrder);
    c.setNotificationUri(getContext().getContentResolver(), url);
    return c;
  }

  @Override
  public int update(Uri url, ContentValues values, String where,
      String[] selectionArgs) {
    String segment = url.getPathSegments().get(1);
    int count = db.update("notes", values, "_id=" + segment
          + (!TextUtils.isEmpty(where)
              ? " AND (" + where + ')'
              : ""),
          selectionArgs);
    getContext().getContentResolver().notifyChange(url, null, true);
    return count;
  }

もの凄くイキオイだけで書いてます。で、さっと試験してみたら例外。Manifest に記述が必要です。

    <provider android:name="com.android.demo.notepad3.NotesProvider"
              android:multiprocess="true"
              android:authorities="com.android.demo.notepad3" />

再度試験したらまた例外、query を以下に修正。

	  @Override
	  public Cursor query(
	      Uri url, String[] projection, String selection, String[] selectionArgs,
	      String sort) {
            Cursor c = db.query(true, "notes", new String[] {"_id",
                  "title", "body"}, selection, null,
                  null, null, null, null);
	    c.setNotificationUri(getContext().getContentResolver(), url);
	    return c;
	  }

で、試験したらレコード追加はできますがレコード選択時に no notes って出力されます。この挙動は何でしょうね。
で、既存のソレを踏襲して以下に直したら更新もできるようになりました。

	  @Override
	  public int update(Uri url, ContentValues values, String where,
	      String[] selectionArgs) {
            int count = db.update("notes", values, where, null);

	    getContext().getContentResolver().notifyChange(url, null, true);
	    return count;
	  }

あと、削除は全部消えます。これはそう書いてました (汗

    public boolean deleteNote(long rowId) {
        return mCtx.getContentResolver().delete(CONTENT_URI, "_id = " + rowId, null) > 0;
    }

あとは画面遷移時に no notes と出るのをなんとかすりゃ良いのでしょうがタイムアップです。別途きちんと纏めます。