为什么SQLiteOpenHelper导致IllegalArgumentException数据库无法打开?

Bev*_*vor 1 android sqliteopenhelper android-sqlite

首先,这里所有类似的帖子都没有帮助.

在AsyncTask中,我检查应用程序启动是否是第一次启动,这意味着我检查是否有数据库.我希望通过表格查询来做到这一点.这是正在执行的内容:

@Override
public List<Entity> loadAll(Entity markerEntity)
{
    Log.i(TAG, "trying to load all entities of type " + markerEntity.getTable());

    List<Entity> results = new LinkedList<Entity>();

    SQLiteDatabase db = defaultSQLiteOpenHelper.getWritableDatabase();

    Cursor cursor = db.query(markerEntity.getTable(), markerEntity.getAllColumns(), null, null, null, null, null);    
    cursor.moveToFirst();

    while (!cursor.isAfterLast())
    {
        Entity result = markerEntity.createNewInstance(cursor);
        results.add(result);

        cursor.moveToNext();
    }

    db.close();

    return results;
}
Run Code Online (Sandbox Code Playgroud)

IllegalArgumentException崩溃:数据库未打开发生在此行上.

SQLiteDatabase db = defaultSQLiteOpenHelper.getWritableDatabase();
Run Code Online (Sandbox Code Playgroud)

它恰好发生在方法(见下文)createAllTables上.

文件说:

创建和/或打开将用于读写的数据库.第一次调用它时,将打开数据库并调用onCreate(SQLiteDatabase),onUpgrade(SQLiteDatabase,int,int)和/或onOpen(SQLiteDatabase).

在我看来,它应该执行我的DefaultSQLiteOpenhelper并创建所有数据库表,但它不会这样做:

public class DefaultSQLiteOpenHelper extends SQLiteOpenHelper implements ISQLiteOpenHelper
{
    private static final String TAG = DefaultSQLiteOpenHelper.class.getSimpleName();

    private static final String DATABASE_NAME = "MY_DATABASE";
    private static final int DATABASE_VERSION = 1;

    @Inject
    public DefaultSQLiteOpenHelper(Context context)
    {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    //is called by the framework if the database doesn't exist
    @Override
    public void onCreate(SQLiteDatabase db)
    {
        Log.i(TAG, "no database found. Generating new database...");

        createAllTables(db);    
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
    {
         Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion);
//       db.execSQL("DROP TABLE IF EXISTS " + TABLE_COMMENTS); ///TODO when upgrade
//       onCreate(db);
    }

    //The order must not be changed because sqlite doesn't allow
    //table modification. That means one cannot add constraints afterwards
    //which results in creating tables in a specific order
    private final void createAllTables(SQLiteDatabase db)
    {
        db.beginTransaction();

        //create lookups at first
        db.execSQL(TableFactory.createUsage());
        db.execSQL(TableFactory.createLanguage());

        db.execSQL(TableFactory.createAccount());
        db.execSQL(TableFactory.createPreferences());
        db.execSQL(TableFactory.createLanguageUsageRel());
        db.execSQL(TableFactory.createPantry());
        db.execSQL(TableFactory.createProduct());

        //populate lookups
        db.execSQL(DataFactory.populateUsage());
        db.execSQL(DataFactory.populateLanguage());

        db.setTransactionSuccessful();
        db.endTransaction();
        db.close();
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是,为什么不打开数据库?文档说它必须.我不接受任何脏的解决方法作为手动打开数据库或其他东西的解决方案.我的代码究竟出了什么问题?我无法相信它是Android中的一个错误.

这是堆栈跟踪:

05-27 17:25:50.370:I/DefaultSQLiteOpenHelper(719):未找到数据库.生成新数据库... 05-27 17:25:50.400:W/dalvikvm(719):threadid = 10:线程退出未捕获异常(组= 0x40015560)05-27 17:25:50.400:E/AndroidRuntime(719) ):致命异常:AsyncTask

1 05-27 17:25:50.400:E/AndroidRuntime(719):java.lang.RuntimeException:执行时发生错误

doInBackground()05-27 17:25:50.400:E/AndroidRuntime(719):at android.os.AsyncTask $ 3.done(AsyncTask.java:200)05-27 17:25:50.400:E/AndroidRuntime(719) :at java.util.concurrent.FutureTask $ Sync.innerSetException(FutureTask.java:274)05-27 17:25:50.400:E/AndroidRuntime(719):at java.util.concurrent.FutureTask.setException(FutureTask.java :125)05-27 17:25:50.400:E/AndroidRuntime(719):at java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:308)05-27 17:25:50.400:E/AndroidRuntime (719):at java.util.concurrent.FutureTask.run(FutureTask.java:138)05-27 17:25:50.400:E/AndroidRuntime(719):at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor. java:1088)05-27 17:25:50.400:E/AndroidRuntime(719):at java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:581)05-27 17:25:50.400:E/AndroidRuntime(719):at java.lang.Thread.run(Thread.java:1019)05-27 17:25:50.400:E/AndroidRuntime(719):引起:java.lang.IllegalStateException:database not op en 05-27 17:25:50.400:E/AndroidRuntime(719):在android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:555)05-27 17:25:50.400:E/AndroidRuntime(719):在android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:137)05-27 17:25:50.400:E/AndroidRuntime(719):at com.mydomain.android.base.persistence.PersistenceManager.loadAll(PersistenceManager. java:58)05-27 17:25:50.400:E/AndroidRuntime(719):at com.mydomain.android.base.main.StartupTask.isFirstStartAfterInstallation(StartupTask.java:107)05-27 17:25:50.400: E/AndroidRuntime(719):at com.mydomain.android.base.main.StartupTask.doInBackground(StartupTask.java:52)05-27 17:25:50.400:E/AndroidRuntime(719):at com.mydomain.android .base.main.StartupTask.doInBackground(StartupTask.java:18)05-27 17:25:50.400:E/AndroidRuntime(719):at android.os.AsyncTask $ 2.call(AsyncTask.java:185)05-27 17:25:50.400:E/AndroidRuntime(719):at java.util.concurrent.FutureTask $ Sync.innerRun(FutureTask.java:306)0 5-27 17:25:50.400:E/AndroidRuntime(719):...还有4个

Com*_*are 5

首先,您要关闭数据库createAllTables().切勿关闭数据库onCreate()onUpgrade()SQLiteOpenHelper.

其次,您的事务逻辑是不必要的createAllTables(),就像onCreate()在事务中执行一样.这很好,因为无论如何,您的事务逻辑都是不正确实现的.

为澄清后一条评论,进行交易的正确方法是:

try {
    db.beginTransaction();

    // SQL

    db.setTransactionSuccessful();
}
// optional catch block
finally {
    db.endTransaction();
}
Run Code Online (Sandbox Code Playgroud)

endTransaction()如果存在SQL异常,则需要调用 - 您的实现会跳过此异常.

  • @ user2336315:"是否允许在AyncTask中获取可写数据库?" - 它不仅是允许的,而且几乎是强制性的,因为`getWriteableDatabase()`如果必须创建或更新数据库,它可以执行重要的磁盘I/O. "我很想说它可能导致并发异常." - 通过查看源代码可以看到,它同步了这项工作. (2认同)