我目前在应用商店中有一个应用程序可用,但有一种类型的错误报告我似乎无法完全弄清楚。我的应用程序使用内部 sqlite 数据库,但在某些设备上(当然不是大多数设备)有时会出现以下错误:
android.database.sqlite.SQLiteException: no such table: image_data (code 1): , while compile: SELECT Min(stamp) FROM image_data WHERE category = 'Astronomy' AND stamp >= 1357426800 and coalesce(title_nl, '') = ' '
我确信这个表存在并且我确信这个查询是正确的。我知道这个错误只发生在应用程序的小部件和 AlarmManager 触发的 BroadcastReceiver 中(应用程序偶尔会尝试下载新条目,因为它是当天应用程序的图片)。
我认为这与我在访问数据库时所处的上下文有关。我有一个名为 AppContextHelper 的类,它扩展了 Application 并有一个静态成员用于存储上下文。访问数据库时始终使用该上下文。
我的问题:在某些情况下,在获取小部件中的数据库或上述由 AlarmManager 触发的 BroadcastReceiver 时,上下文是否无效,在这种情况下,我应该使用提供的上下文来支持“应用程序”上下文?如果是这样,为什么该上下文无效或更好,提供的是哪个上下文?
提前致谢!
根据要求,导致问题的代码再次仅在某些设备上且仅在小部件或 AlarmManager 类中。我将在 AlarmManager 类中发布导致错误的代码(即行数最少的代码)
初始化警报的代码:
Intent myIntent = new Intent(AppContextHelper.getContext(), ApodDownloader.class); mPendingIntent = PendingIntent.getBroadcast(AppContextHelper.getContext(), 0, myIntent, 0); AlarmManager alarmManager = (AlarmManager)AppContextHelper.getContext().getSystemService(Context.ALARM_SERVICE); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis() + 10000, AlarmManager.INTERVAL_HOUR, mPendingIntent);
AppContextHelper.java
public class AppContextHelper extends Application { private static Context mContext; @Override public void onCreate() { super.onCreate(); mContext = this; } public static Context getContext(){ return mContext; } }
(部分)ApodDownloader.java(这包含抛出异常的行)
@Override public void onReceive(Context arg0, Intent arg1) { (new AsyncTaskThreadPool<Integer, Void, Boolean>() { @Override protected Boolean doInBackground(Integer... params) { Helpers.logMessage("Checking new entries."); SQLiteDatabase db = FrescoDatabase.acquireReadableDatabase(AppContextHelper.getContext()); try { >>> THIS LINE THROWS THE EXCEPTION <<< maxStamp = Helpers.executeScalarLong(db, "SELECT Min(stamp) FROM image_data WHERE category = 'Astronomy' AND stamp >= 1357426800 and coalesce(title_nl, '') = ''"); [...] } finally { FrescoDatabase.releaseReadableDatabase(); } [...] more code } [...] onPostExecute }).executeOnExecutor(AsyncTaskThreadPool.THREAD_POOL_EXECUTOR, 0);
FrescoDatabase.java 数据库由应用程序在启动时自动生成,此代码在触发异常的设备上也有效。我不能足够强调数据库存在于有问题的设备上,因为除了小部件和 AlarmManager 的 BroadcastReceiver 之外,应用程序运行完美,所以请不要告诉我数据库未正确初始化:)
public class FrescoDatabase extends SQLiteOpenHelper { public static final String[] OBSOLETE_DATABASE_FILE_NAMES = new String[] { "Fresco.v1.sqlite", "Fresco.v2.sqlite", "Fresco.v3.sqlite", "Fresco.v4.sqlite", "Fresco.v5.sqlite" }; public static final String DATABASE_FILE_NAME = "Fresco.v6.sqlite"; public static final int DATABASE_FILE_SIZE = 15302656; private static final int DATABASE_VERSION = 7; private static final Lock writeLock = new ReentrantLock(); private static SQLiteDatabase currentDB = null; public static final SQLiteDatabase acquireWritableDatabase(Context c) { writeLock.lock(); currentDB = new FrescoDatabase(c).getWritableDatabase(); return currentDB; } public static final void releaseWritableDatabase() { currentDB.close(); currentDB = null; writeLock.unlock(); } public static final SQLiteDatabase acquireReadableDatabase(Context c) { writeLock.lock(); currentDB = new FrescoDatabase(c).getReadableDatabase(); return currentDB; } public static final void releaseReadableDatabase() { currentDB.close(); currentDB = null; writeLock.unlock(); } private FrescoDatabase(Context context) { super(context, InitializeFrescoDatabaseTask.getDatabaseFileName(context), null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { // database is automatically generated, this should not be called } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
(部分)Helpers.java
public class Helpers { [...] public static long executeScalarLong(SQLiteDatabase db, String query) { return executeScalarLong(db, query, new String[] { }); } public static long executeScalarLong(SQLiteDatabase db, String query, String... parameters) { (line 85, see stack trace down below) Cursor cursor = db.rawQuery(query, parameters); try { cursor.moveToNext(); long val = cursor.getLong(0); return val; } catch (Exception e) { ; } finally { cursor.close(); } return -1; } }
异常日志(根据要求):
java.lang.RuntimeException: An error occured while executing doInBackground()
at nl.tagpulse.utils.AsyncTaskThreadPool$3.done(AsyncTaskThreadPool.java:329)
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
at java.util.concurrent.FutureTask.run(FutureTask.java:137)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
at java.lang.Thread.run(Thread.java:856)
Caused by: android.database.sqlite.SQLiteException: no such table: image_data (code 1): , while compiling: SELECT Min(stamp) FROM image_data WHERE category = 'Astronomy' AND stamp >= 1357426800 and coalesce(title_nl, '') = ''
at android.database.sqlite.SQLiteConnection.nativePrepareStatement(Native Method)
at android.database.sqlite.SQLiteConnection.acquirePreparedStatement(SQLiteConnection.java:1012)
at android.database.sqlite.SQLiteConnection.prepare(SQLiteConnection.java:623)
at android.database.sqlite.SQLiteSession.prepare(SQLiteSession.java:588)
at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:58)
at android.database.sqlite.SQLiteQuery.<init>(SQLiteQuery.java:37)
at android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:44)
at android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:1314)
at android.database.sqlite.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1253)
at nl.tagpulse.fresco.other.Helpers.executeScalarLong(Helpers.java:85)
at nl.tagpulse.fresco.other.Helpers.executeScalarLong(Helpers.java:82)
at nl.tagpulse.fresco.business.FrescoDatabase.retrieveNewEntries(FrescoDatabase.java:64)
at nl.tagpulse.fresco.business.ApodDownloader$1.doInBackground(ApodDownloader.java:192)
at nl.tagpulse.fresco.business.ApodDownloader$1.doInBackground(ApodDownloader.java:1)
at nl.tagpulse.utils.AsyncTaskThreadPool$2.call(AsyncTaskThreadPool.java:317)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
... 4 more
我在 Helpers.java 块中添加了第 85 行标记。
希望这可以帮助!