简体   繁体   English

SQLiteAssetHelper NullPointerException仅在某些设备上

[英]SQLiteAssetHelper NullPointerException only on some devices

I am using SQLiteAssetHelper library to deal with my App DB operations and it's working fine for almost every phone I've tested with. 我正在使用SQLiteAssetHelper库来处理我的App DB操作,并且对于我测试过的几乎所有手机,它都可以正常工作。 However some users with Android 2.3.3 - 2.3.7 report crashes when a call to open the db is made. 但是,某些使用Android 2.3.3-2.3.7的用户在调用打开数据库时崩溃。 I suspect this is due to some issue occuring the first time the db is being copied from the asset folder (such as insufficient space in the internal storage). 我怀疑这是由于第一次从资产文件夹复制数据库时发生的某些问题(例如内部存储空间不足)。

Helper class: 助手类:

public class DbHelper extends SQLiteAssetHelper {

    final static String DB_NAME="db";
    static final int DB_VERSION = 1307181213;
    final Context context;

    public DbHelper(Context c) {
        super(c, DB_NAME, null, DB_VERSION);
        this.context = c;
        setForcedUpgradeVersion(DB_VERSION);
    }
}

Handler Class (I set a counter to timeout after 10s if db cannot be opened) : 处理程序类(如果无法打开db,我将计数器设置为10秒后超时):

public class DbHandlerDao {

    private SQLiteDatabase database;
private DbHelper dbHelper;

public DbHandlerDao(Context context) {
    dbHelper = new DbHelper(context);
}

public void open() throws SQLException {
    boolean opened = false;
    int timeout = 0;
    while (!opened && timeout < 10000) {
        try {
            database = dbHelper.getReadableDatabase();
            opened = true; 
        }
        catch (IllegalStateException e) {
            timeout += 500;
            try {
                Thread.sleep(500);
            } catch (Exception e2) {

            }
        }
    }
}

public void close() {
    dbHelper.close();
}

Calling class: 通话类:

private class DbAsyncTask extends AsyncTask<Long, Void, Void> {

        //...

        @Override
        protected Void doInBackground(Long... params) {
            dataHandler.open();

Exception: 例外:

java.lang.RuntimeException: An error occured while executing doInBackground()
    at android.os.AsyncTask$3.done(AsyncTask.java:200)
    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
    at java.lang.Thread.run(Thread.java:1019)
Caused by: java.lang.NullPointerException
    at com.readystatesoftware.sqliteasset.SQLiteAssetHelper.getWritableDatabase(SQLiteAssetHelper.java:180)
    at com.readystatesoftware.sqliteasset.SQLiteAssetHelper.getReadableDatabase(SQLiteAssetHelper.java:257)
    at com.example.DbHandlerDao.open(DbHandlerDao.java:25)
    at com.example.SearchActivity$DbAsyncTask.doInBackground(SearchActivity.java:244)
    at com.example.SearchActivity$DbAsyncTask.doInBackground(SearchActivity.java:1)
    at android.os.AsyncTask$2.call(AsyncTask.java:185)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)

Possibly the users have cleared their storage or they don't have a SD CARD? 可能是用户清除了他们的存储空间,或者他们没有SD卡?

Probably whats going on for sporadic crashes. 零星的崩溃可能是怎么回事。

** Have you implemented the oncreate and onupgrade methods? ** 您是否实现了oncreate和onupgrade方法?

I use the open helper. 我使用开放式助手。 So I never have trouble opening the database. 因此,打开数据库我永远不会遇到麻烦。

 public class RidesDatabaseHandler extends SQLiteOpenHelper {

... ...

    // Creating Tables
@Override
public void onCreate(SQLiteDatabase db) {
    String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_RIDES + "("
            + KEY_ID + " INTEGER PRIMARY KEY," + KEY_NAME + " TEXT,"
            + KEY_DESCRIPTION + " TEXT," + KEY_BOUNDS_NELAT + " TEXT,"
            + KEY_BOUNDS_NELONG + " TEXT," + KEY_BOUNDS_SWLAT + " TEXT,"
            + KEY_BOUNDS_SWLONG + " TEXT," + KEY_RESRAWID + " TEXT,"
            + KEY_RESDRAWABLEID + " TEXT," + KEY_PATH + " TEXT,"
            + " CONSTRAINT UNQ_" + KEY_PATH + " UNIQUE (" + KEY_PATH
            + ") ON CONFLICT ABORT)";

    // VERSION 43 ADDS THE KEY_DATE_UPDATE COLUMN
    CREATE_CONTACTS_TABLE += " , " + KEY_DATE_UPDATE + " INTEGER DEFAULT 0";

    db.execSQL(CREATE_CONTACTS_TABLE);
}

// Upgrading database
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    int upgradeTo = oldVersion + 1;
    while (upgradeTo <= newVersion) {
        switch (upgradeTo) {
        // update old resrawid's to constants
        // this was caused when I saved R values in the database
        // and then later realized they would change.
        // the old resrawid is changed to a constant.
        case 42:
            ContentValues values;
            @SuppressWarnings("unused")
            // used for debugging so I can see the value of the update.
            int res;
            int rs;
            rs = 2130968576;
            values = new ContentValues();
            values.put(
                    KEY_RESRAWID,
                    com.gosylvester.bestrides.ImageTextListViewActivity.SAMPLE_DRAGON);
            res = db.update(TABLE_RIDES, values, KEY_RESRAWID + " = ?",
                    new String[] { String.valueOf(rs) });

            rs = 2130968577;
            values = new ContentValues();
            values.put(
                    KEY_RESRAWID,
                    com.gosylvester.bestrides.ImageTextListViewActivity.SAMPLE_M119);
            res = db.update(TABLE_RIDES, values, KEY_RESRAWID + " = ?",
                    new String[] { String.valueOf(rs) });

            rs = 2130968578;
            values = new ContentValues();
            values.put(
                    KEY_RESRAWID,
                    com.gosylvester.bestrides.ImageTextListViewActivity.SAMPLE_MEDINA);
            res = db.update(TABLE_RIDES, values, KEY_RESRAWID + " = ?",
                    new String[] { String.valueOf(rs) });
            break;
        case 43:
            // new column added for last_viewed.
            db.execSQL(VERSION_43_ALTER);
            break;

        case 44:
            // new index on KEY_DATE_UPDATE DESC
            db.execSQL(VERSION_44_CREATE_INDEX);
        }
        upgradeTo++;
    }

Good Luck 祝好运

This question didn't have an accepted answer even though the OP indicated that it was solved in the comments. 即使OP指出注释中已解决该问题,也没有可接受的答案。 So here is the answer: 所以这是答案:

Don't try to copy the database with an AsyncTask that is called from a method (such as onCreate ) and then try to populate a ListView with data from the database in the same method. 不要尝试使用从方法(例如onCreate )调用的AsyncTask复制数据库,然后尝试使用同一方法中的数据库数据填充ListView If the AsyncTask has not finished by the time the ListView needs the data then a NullPointerException will be raised. 如果ListView需要数据时AsyncTask尚未完成,则将引发NullPointerException。

Instead, populate the ListView from the onPostExecute method of the AsyncTask . 而是从AsyncTaskonPostExecute方法填充ListView That will ensure that the database has finished copying. 这将确保数据库已完成复制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM