【问题标题】:SimpleCursorAdapter does not load external sqlite database: "_id" errorSimpleCursorAdapter 不加载外部 sqlite 数据库:“_id”错误
【发布时间】:2013-03-20 08:26:11
【问题描述】:

错误提示:column _id does not exists 但该列在数据库中(设置为主键),并且该列位于外部 SD 文件夹中。我试图在活动的初始加载时返回数据库中包含的值,但光标似乎没有返回任何内容。

public class ComponentsDbAdapter {

  public static final String COLUMN_ID = "_id";
  public static final String COLUMN_SUBSTRUCTURE = "substructure";
  public static final String COLUMN_TYPE = "type";
  public static final String COLUMN_ORDERNUM = "ordernum";
  public static final String COLUMN_INSTALLATION = "installation";
  private static final String TAG = "ComponentsDbAdapter";
  private DatabaseHelper mDbHelper;
  private SQLiteDatabase mDb;
  private static final String DATABASE_PATH = Environment.getExternalStorageDirectory().getAbsoluteFile()+ "/DATABASE_BACKUP/IMPORTED/";
  private static final String DATABASE_NAME = "android.db";
  private static final String TABLE_NAME = "TAB_WORKSCPE";
  private static final int DATABASE_VERSION = 1; 
  private final Context mCtx;


  public ComponentsDbAdapter open() throws SQLException {
    mDbHelper = new DatabaseHelper(mCtx);
    mDb = mDbHelper.getWritableDatabase();
    return this;
  }

  private static class DatabaseHelper extends SQLiteOpenHelper {
    DatabaseHelper(Context context) {
        super(context, DATABASE_PATH+DATABASE_NAME, null, DATABASE_VERSION);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.query(TABLE_NAME, new String[] {COLUMN_ID, COLUMN_SUBSTRUCTURE, COLUMN_TYPE, COLUMN_ORDERNUM, COLUMN_INSTALLATION}, null, null, null, null, null); 
    }
    @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 " + TABLE_NAME);
        onCreate(db);
    }
  }

  public ComponentsDbAdapter(Context ctx) {
    this.mCtx = ctx;
  }

  public void close() {
    if (mDbHelper != null) {
        mDbHelper.close();
    }
 }

  public Cursor fetchComponentsByName(String inputText) throws SQLException {
    Log.w(TAG, inputText);
    Cursor mCursor = null;
    if (inputText == null  ||  inputText.length () == 0)  {
        mCursor = mDb.query(TABLE_NAME, new String[] {COLUMN_ID, COLUMN_SUBSTRUCTURE, COLUMN_TYPE, COLUMN_ORDERNUM, COLUMN_INSTALLATION}, null, null, null, null, null); 
} else {
    mCursor = mDb.query(true, TABLE_NAME, new String[] {COLUMN_ID, COLUMN_SUBSTRUCTURE, COLUMN_TYPE, COLUMN_ORDERNUM, COLUMN_INSTALLATION}, COLUMN_TYPE + " like '%" + inputText + "%'", null, null, null, null, null);
}
    if (mCursor != null) {
        mCursor.moveToFirst();
    }
    return mCursor; 
}

public Cursor fetchAllComponents() {
    Cursor mCursor = mDb.query(TABLE_NAME, new String[] {COLUMN_ID, COLUMN_SUBSTRUCTURE, COLUMN_TYPE, COLUMN_ORDERNUM, COLUMN_INSTALLATION}, null, null, null, null, null);
    if (mCursor != null) {
        mCursor.moveToFirst();
    }
    return mCursor;
  }
}





public class AndroidListViewCursorAdaptorActivity extends Activity {

private ComponentsDbAdapter dbHelper;
private SimpleCursorAdapter dataAdapter;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    dbHelper = new ComponentsDbAdapter(this);
    dbHelper.open();

    //Generate ListView from SQLite Database
    displayListView();
}

private void displayListView() {
    Cursor cursor = dbHelper.fetchAllComponents();

    // The desired columns to be bound
    String[] columns = new String[] {
        ComponentsDbAdapter.COLUMN_SUBSTRUCTURE,
        ComponentsDbAdapter.COLUMN_TYPE,
        ComponentsDbAdapter.COLUMN_ORDERNUM,
        ComponentsDbAdapter.COLUMN_INSTALLATION
    };

    // the XML defined views which the data will be bound to
    int[] to = new int[] {
        R.id.inst,
        R.id.subdt,
        R.id.type,
        R.id.ordernum,
    };

    // create the adapter using the cursor pointing to the desired data
    //as well as the layout information
    dataAdapter = new SimpleCursorAdapter(
        this, 
        R.layout.country_info,
        cursor,
        columns,
        to,
        0);

    ListView listView = (ListView) findViewById(R.id.listView1);
    // Assign adapter to ListView
    listView.setAdapter(dataAdapter);


    listView.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> listView, View view,
            int position, long id) {
            // Get the cursor, positioned to the corresponding row in the result set
            Cursor cursor = (Cursor) listView.getItemAtPosition(position);

            // Get the state's capital from this row in the database.
            String compSubdt = cursor.getString(cursor.getColumnIndexOrThrow("subdt"));
            Toast.makeText(getApplicationContext(), compSubdt, Toast.LENGTH_SHORT).show();
        }
    });

    EditText myFilter = (EditText) findViewById(R.id.myFilter);
    myFilter.addTextChangedListener(new TextWatcher() {

        public void afterTextChanged(Editable s) {
        }

        public void beforeTextChanged(CharSequence s, int start,int count, int after) {
        }

        public void onTextChanged(CharSequence s, int start,int before, int count) {
            dataAdapter.getFilter().filter(s.toString());
        }
    });

    dataAdapter.setFilterQueryProvider(new FilterQueryProvider() {
        public Cursor runQuery(CharSequence constraint) {
            return dbHelper.fetchComponentsByName(constraint.toString());
        }
    });
 }
 }

【问题讨论】:

  • 看不到您的CREATE TABLE ...db.execSQL("CREATE TABLE ...") 在你onCreate() 中怎么样?
  • 另外,您应该引用复制代码的教程:vogella.com 上的AndroidSQLite
  • 对不起,我应该提到教程的参考:mysamplecode.com/2012/07/… 我知道我想念 CREATE TABLE,因为数据已经存在。我需要另一个光标吗?
  • 解决方案:上面的代码工作正常,但问题出在数据库中。我在数据库中的列都是大写的。除了列 ID 需要始终为小写之外,这将是可以的。因此:'public static final String COLUMN_ID = "_id";' '公共静态最终字符串 COLUMN_SUBSTRUCTURE = "SUBSTRUCTURE";' 'public static final String COLUMN_TYPE = "TYPE";' ...

标签: java android sqlite cursor simplecursoradapter


【解决方案1】:

您的代码中并未显示您已创建表,因此不会找到任何列。

您可以在onCreate 方法中通过创建查询来创建表来执行此操作。在您的代码中,您似乎在进行选择而不是创建。

private static final String TABLE_CREATE = "create table "
    + TABLE_NAME
    + "("
    + COLUMN_ID + " integer primary key autoincrement, "
    + COLUMN_TYPE + " text not null default '', "
    + COLUMN_ORDERNUM + " integer not null default 0, "
    + COLUMN_INSTALLATION + " integer not null default 0, "
    + COLUMN_SUBSTRUCTURE + " text not null default ''"
    + ");";

@Override
public void onCreate(SQLiteDatabase database) {
    database.execSQL(TABLE_CREATE);
}

要将其存储在外部存储中,您需要覆盖 getDatabasePath(...)。类似的解决方案在这里https://stackoverflow.com/a/8385537/935779

@Override
public File getDatabasePath(String name) {
    // reference where you would like the file to be here.
    File result = new File(getExternalFilesDir(null), name);
    return result;
}

我相信你会想用你的 Application 类覆盖它,因为它是 ContextWrapper 的成员。

openOrCreateDatabase(...) 内部使用getDatabaseFile(...) 方法来确定位置。

或者,您可以直接覆盖 openOrCreateDatabase(...) 并在那里设置文件位置。

【讨论】:

  • 我不相信这会创建数据库。您必须通过 sqlite create table 语句定义表结构。您在上面链接的教程有一个 create 语句,但您的代码版本没有。
  • 我希望做的是修改教程,以便在加载列表时也会加载数据。现在,带有 CREATE TABLE 的代码在“如果”数据库不退出时工作正常,我将在 /DATA/DATA/... 中创建它,并通过编辑页面(活动)向它添加一些数据+加载 ok还。但是,一旦我指定了外部数据库的路径,它似乎就无法读取它。如果我没有在清单中包含 android.permission.WRITE_EXTERNAL_STORAGE 它表示它没有写入权限 - 因此我假设它会尝试连接到它。
  • 您需要通过覆盖一个方法来更改我认为的数据库文件位置。我已经更新了答案
  • 是不是和:DATABASE_PATH = Environment.getExternalStorageDirectory().getAbsoluteFile()+ "/DATABASE_BACKUP/IMPORTED/";
  • 我添加了另一种方法来确认它存在,但它仍然无法打开它。
【解决方案2】:

我认为您不能更改甚至指定数据库的位置,只能更改名称。 离开路径,不要尝试将其放在外部存储中 - 让 Android 确定路径。

【讨论】:

    【解决方案3】:

    好的,这花了我将近一周的时间和很大的压力,但这是解决方案。我开始阅读很多教程并在这个教程中使用它:

    http://www.mysamplecode.com/2012/11/android-database-content-provider.html

    我从虚拟设备中提取了数据库并手动添加了更多数据。然后将数据库复制到我的设备文件夹上的所需文件夹(只是为了确保数据库一致性/列完全相同)。然后将 MyDatabaseHelper 类更改如下:

    public class MyDatabaseHelper extends SQLiteOpenHelper {
    
        private static final String DATABASE_PATH = Environment.getExternalStorageDirectory().getAbsoluteFile()+ "/MYFOLDER/";
        private static final String DATABASE_NAME = "TheWorld.db";
        private static final int DATABASE_VERSION = 1;
    
        MyDatabaseHelper(Context context) {
            super(context, DATABASE_PATH+DATABASE_NAME, null, DATABASE_VERSION);
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            CountriesDb.onCreate(db);
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            CountriesDb.onUpgrade(db, oldVersion, newVersion);
        }
    }
    

    不要忘记为清单添加权限:

    <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    

    完成! 如果您阅读上面的帖子,答案是基于柯克斯的建议,因此阅读他推荐的链接会有所帮助。我还有更多的测试要做,以防我之前的数据库结构错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-16
      • 1970-01-01
      • 2014-02-24
      • 1970-01-01
      相关资源
      最近更新 更多