У меня есть приложение, доступное в настоящее время в магазине приложений, но есть один тип отчета об ошибке, который я, похоже, не могу полностью понять. В моем приложении используется внутренняя база данных sqlite, но на некоторых устройствах (конечно, не в большинстве) иногда возникает следующая ошибка:
android.database.sqlite.SQLiteException: нет такой таблицы: image_data (код 1): при компиляции: SELECT Min (штамп) FROM image_data ГДЕ категория = 'Астрономия' AND stamp >= 1357426800 и coalesce (title_nl, '') = ''
Я уверен, что эта таблица существует, и я уверен, что этот запрос верен. Я знаю, что эта ошибка возникает только в виджетах приложения и в BroadcastReceiver, запущенном AlarmManager (приложение раз в то время пытается загрузить новые записи, так как это изображение рабочего дня).
Я думаю, что это имеет какое-то отношение к Контексту, в котором я участвую при доступе к базе данных. У меня есть класс под названием AppContextHelper, который расширяет приложение и имеет статический член, в котором я храню контекст. Этот контекст всегда используется при доступе к базе данных.
Мой вопрос: может быть, что этот контекст недействителен в некоторых случаях при приобретении базы данных в виджетах или вышеупомянутом BroadcastReceiver, выпущенном AlarmManager, и что в этом случае я должен использовать предоставленный контекст в пользу "приложения", контекст? Если да, то почему этот контекст недействителен или еще лучше, какой контекст он предоставляется?
Спасибо заранее!
Как запросил код, приводящий к этой проблеме, опять же, только на НЕКОТОРЫХ устройствах и ТОЛЬКО в виджетах или в классе 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 База данных автоматически создается приложением при запуске, этот код работает, а также на устройствах, которые запускают исключение. Я не могу подчеркнуть, что база данных существует на проблемных устройствах, поскольку приложение работает безупречно, за исключением виджетов и BroadcastReceiver AlarmManager, поэтому, пожалуйста, не говорите мне, что db не инициализирован правильно:)
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
Я добавил маркер строки 85 в блок Helpers.java.
Надеюсь, это поможет!