且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

SQLiteAssetHelper NullPointerException异常仅在某些设备上

更新时间:2023-11-19 14:28:52

这个问题并没有一个公认的答案,即使OP表示,它解决了评论。因此,这里的答案是:

不要试图复制数据库的的AsyncTask 这是从方法称为(如的onCreate ),然后尝试在相同的方法从数据库中填充的ListView 数据。如果的AsyncTask 并没有被当时的的ListView 需要那么一个NullPointerException异常将被提出的数据完成了。

相反,填充的ListView 从的 onPostExecute 方法的AsyncTask 。这将确保数据库完成复制

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. However some users with Android 2.3.3 - 2.3.7 report crashes when a call to open the db is made. 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) :

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)

This question didn't have an accepted answer even though the OP indicated that it was solved in the comments. 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. If the AsyncTask has not finished by the time the ListView needs the data then a NullPointerException will be raised.

Instead, populate the ListView from the onPostExecute method of the AsyncTask. That will ensure that the database has finished copying.