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

时间:2013-05-27 17:34:04

标签: android android-sqlite sqliteopenhelper

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

在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;
}

此行发生 IllegalArgumentException:数据库未打开的崩溃。

SQLiteDatabase db = defaultSQLiteOpenHelper.getWritableDatabase();

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

documentation说:

  

创建和/或打开将用于阅读和的数据库   写作。第一次调用它时,将打开数据库   和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();
    }
}

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

这是stacktrace:

  

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:   数据库未打开05-27 17:25:50.400:E / AndroidRuntime(719):at   android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:555)   05-27 17:25:50.400:E / AndroidRuntime(719):at   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)   05-27 17:25:50.400:E / AndroidRuntime(719):... 4 more

1 个答案:

答案 0 :(得分:5)

首先,您要关闭createAllTables()中的数据库。切勿从onCreate()的{​​{1}}或onUpgrade()关闭数据库。

其次,SQLiteOpenHelper中不需要您的事务逻辑,因为createAllTables()在事务中执行。这很好,因为无论如何你的交易逻辑都是不正确的。

为了澄清后面的评论,正确的交易方式是:

onCreate()

如果存在SQL异常,则需要调用try { db.beginTransaction(); // SQL db.setTransactionSuccessful(); } // optional catch block finally { db.endTransaction(); } - 您的实现会跳过此内容。