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()
的代码之间不能存在竞争,我在这里发布了异步任务的另一个问题: