現在、アプリ ストアでアプリを入手できますが、完全に把握できないエラー レポートが 1 つあります。私のアプリは内部の sqlite データベースを使用していますが、一部のデバイス (確かに大部分ではありません) では、次のエラーが発生することがあります。
android.database.sqlite.SQLiteException: そのようなテーブルはありません: image_data (コード 1): 、コンパイル中: SELECT Min(stamp) FROM image_data WHERE カテゴリ = '天文学' AND スタンプ >= 1357426800 および 合体 (title_nl, '') = ' '
このテーブルが存在すると確信しており、このクエリが正しいと確信しています。このエラーは、アプリのウィジェットと、AlarmManager によって起動される BroadcastReceiver でのみ発生することがわかっています (アプリは、その日のアプリの画像であるため、時々新しいエントリをダウンロードしようとします)。
データベースにアクセスするときのコンテキストと関係があると思います。Application を拡張し、コンテキストを格納する静的メンバーを持つ AppContextHelper というクラスがあります。そのコンテキストは、データベースにアクセスするときに常に使用されます。
私の質問: 場合によっては、ウィジェットでデータベースを取得するとき、または 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 行目のマーカーを追加しました。
お役に立てれば!