- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我目前在应用商店中有一款应用可用,但有一种错误报告我似乎无法完全弄清楚。我的应用程序使用内部 sqlite 数据库,但在某些设备上(当然不是大多数)有时会出现以下错误:
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, '') = ''
我确信这个表存在并且我确信这个查询是正确的。我知道这个错误只发生在应用程序的小部件和 AlarmManager 触发的 BroadcastReceiver 中(应用程序偶尔会尝试下载新条目,因为它是当天应用程序的图片)。
我觉得和我访问数据库时所处的Context有关系。我有一个名为 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 block 中添加了第 85 行标记。
希望这对您有所帮助!
最佳答案
这是发生了什么:
ApodDownloader 是一个 BroadcastReceiver,在它的 onReceive() 中你启动了某种不允许的 AsyncTask。文档指出:
A BroadcastReceiver object is only valid for the duration of the call to onReceive(Context, Intent). Once your code returns from this function, the system considers the object to be finished and no longer active.
This has important repercussions to what you can do in an onReceive(Context, Intent) implementation: anything that requires asynchronous operation is not available, because you will need to return from the function to handle the asynchronous operation, but at that point the BroadcastReceiver is no longer active and thus the system is free to kill its process before the asynchronous operation completes.
http://developer.android.com/reference/android/content/BroadcastReceiver.html#ReceiverLifecycle
当进程被终止时,应用程序上下文不再可用。您仍然可以访问 AppContextHelper.getContext() 但这将是一个新加载的类,因为旧的类在消除进程时被杀死。换句话说,返回的上下文将为空。只有在极少数情况下才会发生这种情况,即 Android 确实终止了一个进程,这在我的经验中并不常见。
如果您的 AppContextHelper 提供的 Context 尚未初始化,那么您的 InitializeFrescoDatabaseTask.getDatabaseFileName(context) 调用将返回一个空字符串,它自然会打开错误的数据库。因为您在 FrescoDatabase 类的 onCreate() 中未执行任何操作,所以数据库未正确初始化并且找不到表。但即使您创建了表,它也可能是错误的数据库,尽管崩溃已经消失,但它不会显示任何数据。
为防止这种情况发生,您需要在运行 onReceive() 的同一个线程中完成所有工作,或者如果这花费的时间太长,则启动服务来完成繁重的工作。
在分析您的代码时我注意到的另一件事是,您在创建警报时使用应用程序上下文来创建 Intent (new Intent(AppContextHelper.getContext(), ApodDownloader.class);)。执行此操作时,您需要设置 FLAG_ACTIVITY_NEW_TASK,否则您可能会收到“android.util.AndroidRuntimeException:从 Activity 上下文外部调用 startActivity() 需要 FLAG_ACTIVITY_NEW_TASK 标志。这真的是您想要的吗?”这可能会使应用程序崩溃,也可能不会。
关于android - 极少数情况下出现 "android.database.sqlite.SQLiteException: no such table"错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15943534/
我有一段代码: try { //sniping out a bunch of irrelevant code here result = cmd.ExecuteScalar();
我有一项服务(在下面列出)正在尝试创建数据库表。当 PlayerTable 的 onCreate() 中的 sql 被执行时,我得到一个异常我不明白。下面列出了所有代码。基本上,服务启动,获取一个 S
从SQLite查询数据时,它说: SQLite错误提供给命令的参数不足 我认为这是一个错误,或者错误消息具有误导性。 因为我只有一个参数并且正在提供它,所以我无法理解问题出在哪里。 这是我的代码: p
我正在尝试使用 SQLite 运行 NHibernate 集成测试。 NHibernate 的 SchemaExport 将根据我的映射文件为我设置数据库。除了我的触发器之外,这工作得很好。 .hbm
我想执行一个 ManagedQuery 但我在我的日志中收到一个错误: 查询 Cursor cursor = managedQuery(GroceryListContentProvider.NOTE
我明白了 android.database.sqlite.SQLiteException: near "WHERE": syntax error (code 1): , while compiling
当我尝试访问我的 View 时出现此错误 我已经使用它构建了我的数据库/ View CREATE TABLE Boxer( BoxerId INTEGER PRIMARY KEY AUTOINCREM
我有这个代码: String sql="UPDATE LAST_OPEN SET LAST_OPEN="+DATE+" WHERE STUDENT_ID ="+STUDENT_I
我在 SQLite 数据库上工作得很好,但现在我在使用查询时遇到了问题。例如,如果使用这样的查询: SQLiteDatabase db = mHelper.getReadableDatabase();
谁知道这是什么意思?我正在尝试在 onActivityResult() 中启动事务以根据收到的结果插入一行。 03-05 15:39:51.937: ERROR/Database(2387): Fai
插入sqlite3数据库失败的可能原因是什么?来自 SQLiteException 的跟踪并不是特别有用。 是否有任何方法可以更好地了解导致异常的原因? 创建表格的位置(抱歉任何不稳定的间距): ht
我正在 try catch “android.database.sqlite.SQLiteException:错误代码 5:数据库已锁定”异常: try { db.insert
我最近在市场上发布了一个应用程序。从开发者控制台看来,我的用户中大约有 1-2% 遇到了这个问题。 1-2% 很小,但人们更倾向于在某些东西不起作用时发表评论,而不是在它起作用时发表评论,这可能会对下
@SuppressLint({"RxLeakedSubscription", "RxSubscribeOnError"}) public static long pushAppointmentsToC
这是从SQLiteDatebase获取表RECORD的代码。在 try block 中出现问题并且总是抛出 SQLiteException。我在这里想做的就是将表“RECORD”的每一行转换为字符串并
我整个上午都在研究此错误的其他实例,但到目前为止我所尝试的一切都不起作用。这可能是显而易见的事情,因为我对此很陌生。 我正在尝试返回 GET_ALL_INGREDIENTS 查询的结果。然后我会将其放
我有一个包含两个表的数据库,每次我尝试向第二个表添加新项目时,它都会说没有这样的表。请帮忙。 数据库助手: @Override public void onCreate(SQLiteDatab
所以我对 SQL 很陌生。我正在尝试将 xml 文件放入我可以搜索的数据库中。我有语法错误,但看不到它/不够熟悉,无法看到它。这是我的 onCreate 方法 protected void onCr
大家好,我在数据库处理程序类中有这个方法,这个类的作用是从产品表中返回产品的 ID。但是,我收到了这个 sqliteException,我不知道为什么。请指教,谢谢。 private stat
我正在构建一个锻炼日志应用程序作为一个项目。我正在尝试将锻炼名称插入数据库。在提示用户添加练习之前。目前它显示“出现问题错误”,然后应用程序崩溃。 下面是Logcat中的错误 android.data
我是一名优秀的程序员,十分优秀!