SQLiteAssetHelper NullPointerException 仅在某些设备上
Posted
技术标签:
【中文标题】SQLiteAssetHelper NullPointerException 仅在某些设备上【英文标题】:SQLiteAssetHelper NullPointerException only on some devices 【发布时间】:2014-01-08 17:07:15 【问题描述】:我正在使用 SQLiteAssetHelper 库来处理我的 App DB 操作,它几乎适用于我测试过的所有手机。但是,一些使用 android 2.3.3 - 2.3.7 的用户在调用打开数据库时报告崩溃。我怀疑这是由于第一次从资产文件夹复制数据库时发生的一些问题(例如内部存储空间不足)。
助手类:
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);
处理程序类(如果无法打开数据库,我将计数器设置为 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();
调用类:
private class DbAsyncTask extends AsyncTask<Long, Void, Void>
//...
@Override
protected Void doInBackground(Long... params)
dataHandler.open();
例外:
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)
【问题讨论】:
我在运行 Android 4.3 和 4.4 的几台设备上遇到了似乎相同的错误。奇怪的是,我无法始终如一地重现它。 我会将它作为 github 项目本身的问题发布,因为它几乎可以保证是库的问题 - 标准 SQLiteOpenHelper 没有这个问题。似乎其他人也有这个问题:github.com/jgilfelt/android-sqlite-asset-helper/issues/23 谢谢,好主意。但经过更多调查后,我意识到这是我自己的错误。长话短说,我正在从一个活动的onCreate
方法调用的AsyncTask
中复制一个数据库,然后尝试使用同一个数据库填充ListView
。事实证明,只有当我很幸运并且后台任务在 ListView
需要数据库之前完成时才有效!
只是快速说明没有基于计时器的循环,用户无法取消。您最终可能会锁定 ui 线程,并且您的应用将显示无响应。
danny117,我在后台运行的 asyncTask 中调用 dataHandler.open()
【参考方案1】:
可能是用户已清空存储空间或没有 SD 卡?
偶尔发生的崩溃可能是怎么回事。
** 你实现了oncreate和onupgrade方法了吗?
我使用 open 助手。所以我从来没有遇到过打开数据库的麻烦。
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++;
祝你好运
【讨论】:
【参考方案2】:即使 OP 表明它已在 cmets 中解决,这个问题也没有被接受的答案。所以这里是答案:
不要尝试使用从方法(例如onCreate
)调用的AsyncTask
复制数据库,然后尝试使用同一方法中的数据库中的数据填充ListView
。如果 AsyncTask
在 ListView
需要数据时尚未完成,则会引发 NullPointerException。
而是从AsyncTask
的onPostExecute
方法填充ListView
。这将确保数据库已完成复制。
【讨论】:
以上是关于SQLiteAssetHelper NullPointerException 仅在某些设备上的主要内容,如果未能解决你的问题,请参考以下文章
Android开发中java.lang.RuntimeException: Unable to start activity ComponentInfo{xxx}: java.lang.NullPoi
Android开发中java.lang.RuntimeException: Unable to start activity ComponentInfo{xxx}: java.lang.NullPoi
我应该如何通知用户 SQLite Asset Helper 第一次加载数据库?