メモ帳の例で機能するものに問題があります。 NotepadCodeLab/Notepadv1Solutionのコードは次のとおりです。
_String[] from = new String[] { NotesDbAdapter.KEY_TITLE };
int[] to = new int[] { R.id.text1 };
SimpleCursorAdapter notes = new SimpleCursorAdapter(this,
R.layout.notes_row, c, from, to);
_
このコードは正常に動作するようです。しかし、明確にするために、 [〜#〜] adb [〜#〜] ユーティリティを実行し、SQLite 3を実行しました。次のようにスキーマを検査しました。
sqlite> .schema
_CREATE TABLE Android_metadata (locale TEXT);
CREATE TABLE notes (_id integer primary key autoincrement, title text
not null, body text not null);
_
すべてが私には良いようです。
さて、私のアプリケーションを見てみましょう。これは、見る限りでは、いくつかの小さな変更を加えても基本的に同じです。コードを単純化および単純化しましたが、問題は解決しません。
_String[] from = new String[] { "x" };
int[] to = new int[] { R.id.x };
SimpleCursorAdapter adapter = null;
try
{
adapter = new SimpleCursorAdapter(this, R.layout.circle_row, cursor, from, to);
}
catch (RuntimeException e)
{
Log.e("Circle", e.toString(), e);
}
_
アプリケーションを実行すると、Log.e()
ステートメントからRuntimeExceptionが取得され、LogCatに次の出力が表示されます。
LogCatメッセージ:
Java.lang.IllegalArgumentException:列 '_id'は存在しません
そこで、SQLite 3に戻って、私のスキーマの違いを確認します。
sqlite> .schema CREATE TABLE Android_metadata(ロケールTEXT); CREATE TABLE circles(_id integer primary key autoincrement、sequence integer、radius real、x real、y real);
「_id」が欠落している方法がわかりません。
私は何を間違えましたか?
私のアプリケーションとメモ帳の例との違いの1つは、Eclipseウィザードを使用してアプリケーションを最初から作成することから始めましたが、サンプルアプリケーションは既にまとめられています。新しいアプリケーションでSQLiteデータベースを使用するために、何らかの環境変更が必要ですか?
カーソルには
_id
という名前の列が含まれている必要があります。そうでない場合、このクラスは機能しません。
SimpleCursorAdapter
は派生クラスであるため、このステートメントが適用されるようです。しかし、この声明は技術的に間違っており、初心者を多少誤解させます。カーソルのresult setには、カーソル自体ではなく_id
が含まれている必要があります。
この種の速記文書は彼らにとって明らかであるため、これはDBAにとって明らかであると確信しています。カーソルはイテレータまたはポインタのようなもので、データを移動するためのメカニズムのみが含まれ、列自体は含まれません。
Loaders documentation には、_id
がprojectionパラメーターに含まれていることがわかる例が含まれています。
static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
Contacts._ID,
Contacts.DISPLAY_NAME,
Contacts.CONTACT_STATUS,
Contacts.CONTACT_PRESENCE,
Contacts.PHOTO_ID,
Contacts.LOOKUP_KEY,
};
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// ...
return new CursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION, select, null,
Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
これは 回答済み でした。ここでより包括的にしたいと思います。
SimpleCursorAdapterでは、カーソルの結果セットに正確に「_id」という名前の列が含まれている必要があります。テーブルで「_id」列を定義しなかった場合、スキーマを変更するのを急がないでください。 SQLiteは、すべてのテーブルに「rowid」という非表示列を自動的に追加しました。必要なことは、rowidを明示的に選択し、「_ id」としてエイリアスするだけです。
SQLiteDatabase db = mHelper.getReadableDatabase();
Cursor cur = db.rawQuery( "select rowid _id,* from your_table", null);
Tim Wuのコードは本当に機能しています...
Db.queryを使用している場合、次のようになります...
db.query(TABLE_USER, new String[] {
"rowid _id",
FIELD_USERNAME,
},
FIELD_USERNAME + "=" + name,
null,
null,
null,
null);
はい、SELECT文字列クエリも変更してこの問題を修正します。
String query = "SELECT t.*,t.id as _id FROM table t ";
このエラーの問題を解決したのは、DBクエリに_id列を含めなかったことです。それを追加することで問題が解決しました。
これはおそらくもう関係ないでしょうが、私は今日同じ問題にぶつかりました。列名では大文字と小文字が区別されます。 _ID列がありましたが、Androidには_id列が必要です。
Sqliteでドキュメントを読む場合、INTEGER PRIMARY KEY型の列を作成するとROWIDが内部的にエイリアスされるため、すべてのSELECTでエイリアスを追加する手間をかける価値はありません。テーブルを定義する列の列挙。
http://www.sqlite.org/autoinc.html
_IDがROWIDから逸脱する可能性があるAUTOINCREMENTオプションの代わりに、これをROWIDとして使用する方が簡単です。 _IDをROWIDに関連付けることは、主キーがinsert/insertOrThrowから返されることを意味します。 ContentProviderを作成している場合、返されたUriでこのキーを使用できます。
テーブルに_id列がないことを処理する別の方法は、必要に応じて_id列を追加するCursorWrapperのサブクラスを記述することです。
これには、テーブルやクエリを変更する必要がないという利点があります。
このようなクラスを作成しました。興味がある場合は、 https://github.com/cmgharris/WithIdCursorWrapper で見つけることができます。