2

I declared the _ID auto increment column in the ContentProvider running on SQLite, and yet I get the following "no such column: _id" error message in the stacktrace, how do I fix this error?

 FATAL EXCEPTION: AsyncTask
 java.lang.RuntimeException: An error occured while executing doInBackground()
 Caused by: android.database.sqlite.SQLiteException: no such column: _id:,
 while compiling: SELECT _id, title, text FROM notes

another strange thing is that I did not call the query method of the contentProvider class anywhere in my code and yet I got the location of the error as a line of code in this query method of the ContentProvider class, if the ContentProvider's query method is not being called then it should not be in the stacktrace, however it is, here is where it tells me the location of the error in the stacktrace

com.example.contentproviderexample.ProviderExample.query(ProviderExample.java:132)

ContentProvider class ProviderExample line 132

Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder);

EDIT: after it was suggested that I uninstall or delete data from the app and run again, after I did that I got a different error from the stacktrace, here it is:

 Couldn't open notes.db for writing (will try read-only):
 android.database.sqlite.SQLiteException:
 AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY:
 , while compiling: CREATE TABLE IF NOT EXISTS
 notes (_id ID INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, text TEXT);

and here is the complete query method of the ContentProvider class

 @Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
    qb.setTables(TABLE_NAME);
    qb.setProjectionMap(notesProjectionMap);
         switch(sUriMatcher.match(uri)){
         case NOTES:
             break;
         case NOTES_ID:
             selection = selection + "_id=" + uri.getLastPathSegment();
             break;
         default:
             throw new IllegalArgumentException("Unknown URI" + uri);    
         }
         SQLiteDatabase db = dbHelper.getReadableDatabase();
         Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder); // <-- no colunn _ID error here
         c.setNotificationUri(getContext().getContentResolver(), uri);
         return c

here is more of the code from the ProviderExample class that extends ContentProvider

 public class ProviderExample extends ContentProvider {

public static final String DATABASE_NAME = "notes.db";
public static final int DATABASE_VERSION = 1;
public static final String TABLE_NAME = "notes";
public static final String AUTHORITY = "com.example.contentproviderexample.providerexample";
public static final UriMatcher sUriMatcher;
private static final int NOTES = 1;
private static final int NOTES_ID = 2;
private static HashMap<String, String> notesProjectionMap;

 static {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(AUTHORITY, TABLE_NAME, NOTES);
        sUriMatcher.addURI(AUTHORITY, TABLE_NAME + "/#", NOTES_ID);
    }

 public static interface NoteItems extends BaseColumns {

        // notes in the CONTENT_URI is often plural where the actual table name is often singular version of this word
        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes");
        public static final String _ID = "_id";
        public static final String TITLE = "title";
        public static final String TEXT = "text";
        public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/vnd.example.providerexample";
        // static final String SINGLE_RECORD = "vnd.android.cursor.item/vnd.example.providerexample";
        public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/vnd.example.providerexample";
        // static final String MULTIPLE_RECORDS = "vnd.android.cursor.dir/vnd.example.providerexample"; 
        public static final String[] PROJECTION_ALL = {_ID, TITLE, TEXT};
        public static final String SORT_ORDER_DEFAULT = TITLE + " ASC";

 }

 private static class DatabaseHelper extends SQLiteOpenHelper{

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

     @Override
     public void onCreate(SQLiteDatabase db) {
     db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + NoteItems._ID + " ID INTEGER PRIMARY KEY AUTOINCREMENT, " +  
             NoteItems.TITLE + " TEXT, " + NoteItems.TEXT + " TEXT);");
     }

     @Override
     public void onUpgrade(SQLiteDatabase db, int previousVersion, int newVersion) {
     db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
     onCreate(db);
     }

 }

private DatabaseHelper dbHelper;

@Override
public boolean onCreate() {
    dbHelper = new DatabaseHelper(getContext());
    return true;
}

@Override
public String getType(Uri uri) {
    switch (sUriMatcher.match(uri)){
        case NOTES:
            return NoteItems.CONTENT_TYPE;
        case NOTES_ID:
            return NoteItems.CONTENT_ITEM_TYPE;
        default:
            throw new IllegalArgumentException("Unknown URI" + uri);
    }

} 

and here is the MainActivity class

   public class MainActivity extends Activity implements LoaderManager.LoaderCallbacks<Cursor>{

private SimpleCursorAdapter adapter;
private LoaderManager loaderManager;
private CursorLoader cursorLoader;
private ListView listView;
private int primaryKey;
private String primaryKeyString;
private String testTitle;
private String testText;
private static final int LOADER_ID = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    primaryKey = 0;
    testTitle = "test title";
    testText = "test text";

    ProviderExample providerExample = new ProviderExample();

    primaryKeyString = String.valueOf(primaryKey);
    getLoaderManager().initLoader(LOADER_ID, null, this);
    adapter = new SimpleCursorAdapter(this, R.layout.row_layout, null,
            new String[]{primaryKeyString, testTitle, testText}, new int[]{R.id.textView1, R.id.textView2, R.id.textView3},
            Adapter.NO_SELECTION);
    listView = (ListView) findViewById(R.id.listView1);
    listView.setAdapter(adapter);

    // load database with test values
    //loadDatabase();

}

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    String[] projection = {ProviderExample.NoteItems._ID, ProviderExample.NoteItems.TITLE, ProviderExample.NoteItems.TEXT };
    cursorLoader = new CursorLoader(this, ProviderExample.NoteItems.CONTENT_URI, projection, null, null, null);
    return cursorLoader;
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    adapter.swapCursor(cursor);
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
    adapter.swapCursor(null);
}
 }
4

2 回答 2

1
@Override
     public void onCreate(SQLiteDatabase db) {
     db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + NoteItems._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +  
             NoteItems.TITLE + " TEXT, " + NoteItems.TEXT + " TEXT);");
     }  

更改卸载后再次运行

于 2013-05-15T04:32:05.140 回答
1

我认为在创建表格时你做错了。您已经在引号内给出了“ ID ”,而且您还拥有NoteItems._ID将“_id ID”作为主要 ID。所以你可能需要纠正它..!!

 @Override
 public void onCreate(SQLiteDatabase db) {
 db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + NoteItems._ID + " ID INTEGER PRIMARY KEY AUTOINCREMENT, " +  
         NoteItems.TITLE + " TEXT, " + NoteItems.TEXT + " TEXT);");
 }
于 2013-05-15T04:23:34.193 回答