Android 暂停/恢复状态行为
我在我的应用程序中看到Android 暂停/恢复状态行为,android,activity-lifecycle,Android,Activity Lifecycle,我在我的应用程序中看到onPause/onResume出现了一些奇怪的行为,无法了解发生了什么 我在onResume中执行数据库查询(简单的AsyncTask子类),如果仍在执行,则在onPause中取消查询。我收到一份崩溃报告,它让我怀疑任务取消是否有效,因此添加了一个分析事件来记录onPostExecute在onPause取消任务后被调用的情况 在过去的一个月里,我在4100次页面浏览中看到了140次这样的活动 @Override protected void onResume() {
onPause
/onResume
出现了一些奇怪的行为,无法了解发生了什么
我在onResume
中执行数据库查询(简单的AsyncTask
子类),如果仍在执行,则在onPause
中取消查询。我收到一份崩溃报告,它让我怀疑任务取消是否有效,因此添加了一个分析事件来记录onPostExecute
在onPause
取消任务后被调用的情况
在过去的一个月里,我在4100次页面浏览中看到了140次这样的活动
@Override
protected void onResume() {
super.onResume();
mIsResumed = true;
if (mReverseCardsTask == null) {
mReverseCardsTask = new TcgCursorTask(this) {
@Override
protected Cursor doInBackground(Void... params) {
return mDb.reverseFetchCards();
}
@Override
protected void onPostExecute(Cursor cursor) {
if (mIsResumed) {
onReverseCardsCursor(cursor);
} else {
EasyTracker.getTracker().sendEvent("error", "on-post-execute", "called after paused", 1L);
}
}
};
mReverseCardsTask.execute();
}
}
@Override
protected void onPause() {
super.onPause();
mIsResumed = false;
if (mReverseCardsTask != null) {
mReverseCardsTask.cancel(false);
mReverseCardsTask = null;
}
}
我有一种感觉,我在这里错过了一些非常简单的东西,但我看不到
我只是注意到我没有在onPostExecute
中清除mReverseCardsTask
,但这不重要。只调用cancel()没有任何作用。实际上,您必须在流程中进行检查,以确定是否要取消该流程,并执行取消该流程的工作
操作系统不知道您在停止之前需要做什么来清理(如关闭文件或打开网络连接)。好。我已经解决了。我不确定它是在哪个API版本中修复的,但是如果您查看姜饼的代码,在
cancel()
处理中有一个明显的争用条件。处理来自后台的MESSAGE\u POST\u结果
消息的GUI线程代码调用onPostExecute()
,无论任务是否被取消
事实证明,解决方法非常简单。我所需要做的就是在执行我的onPostExecute()
逻辑之前添加我自己对isCancelled()的检查
接收消息\u POST\u结果
并调用finish()
。然后finish()
调用onPostExecute()
可以发布堆栈跟踪吗?那会有很大帮助。我没有堆栈跟踪。这在我发布的应用程序中发生。我从来没有亲眼看到过这种事情发生,我可以看到我在代码中加入的分析事件来证实我的怀疑。我刚刚查看了姜饼中的AsyncTask
代码。它有一个错误,在处理来自后台线程的消息\u POST\u结果
消息之前,它不会检查任务是否已取消。真烦人。这意味着有一个竞争条件使得cancel()
语义更加复杂。根据上面的代码,调用cancel()
应该可以防止AsyncTask
在从线程接收到MESSAGE\u POST\u RESULT
消息时调用onPostExecute()
。但是我在AsyncTaskLoader上也遇到了同样的问题。阻止它抛出各种异常的唯一方法是让onStopLoading()方法也在SQLiteDatabaseHelper中设置一个标志,这样我就可以在我必须向DB添加项的各种循环中检查它。如果没有任何检查,它将永远不会停止线程,并且在我下次启动它时它仍将运行,导致SQLite异常。这可能是并发问题。在某些设备上,在UI线程上设置该标志的速度可能不够快,后台线程无法在调用onPostExecute()之前看到它。AsyncTask被认为是有问题和有缺陷的。我可能误解了处理程序的工作原理,但我认为关键是handleMessage()
方法在GUI线程上执行。这意味着取消任务的onPause()
代码与调用onCancelled()
或onPostExecute()
的代码之间不能存在竞争,我在这里发布了异步任务的另一个问题: