是否可以在onDestroy之后调用回调方法? [英] Is it possible for a callback method to be called after onDestroy?
问题描述
在我的应用程序的最新版本中,一些用户遇到了我无法重现的崩溃.当前只有运行Lollipop
的Samsung
设备有此问题,但这可能只是巧合.
在分析了堆栈跟踪和相关代码之后,我认为我可能已经找到了罪魁祸首.为了验证我的假设,我将代码简化为以下代码段:
In the latest version of my app, some users are experiencing a crash that I'm unable to reproduce. Currently only Samsung
devices running Lollipop
are having the issue, but that might just be coincidence.
After analyzing the stack trace and relevant code, I think that I may have found the culprit. To test my assumption, I simplified the code to the snippet below:
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button b = new Button(this);
b.setText("Click me!");
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Handler().post(new Runnable() {
@Override
public void run() {
// This is the callback method
Log.d("TAG", "listenerNotified");
}
});
}
});
setContentView(b);
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d("TAG", "onDestroy");
}
}
每次我通过先点击 Click me 按钮,然后在onDestroy()
之前将后退按钮listenerNotified
打印到控制台上,来测试上述应用程序.
Every time I test the above application by first tapping the Click me button and then the back button, listenerNotified
is printed to the console before onDestroy()
.
但是我不确定我是否可以依靠这种行为. Android
是否可以保证上述情况?我可以安全地假设我的Runnable
总是在onDestroy()
之前执行,还是有一种情况并非如此?在我的真实应用程序中,当然还有很多事情发生(例如其他线程发布到主线程中以及回调中发生了更多操作).但是,这个简单的代码片段似乎足以证明我的关注.
I'm however not sure if I can rely on this behavior. Does Android
make any guarantees about the above scenario? Can I safely assume that my Runnable
will always be executed before onDestroy()
or is there a scenario where that won't be the case? In my real app, there is of course a lot more happening (like other threads posting to the main thread and more operations happening in the callback). But this simple snippet seemed sufficient to demonstrate my concern.
我是否有可能(可能由于其他线程或发布到主线程的回调的影响)在下面获得调试输出?
Is it every possible (possibly due to the influence of other threads or callbacks posted to the main thread) that I get the debug output below?
D/TAG: onDestroy
D/TAG: listenerNotified
我想知道这一点,因为可能的结果可以解释这次崩溃.
I would like to know this, since that outcome being possible would explain the crash.
推荐答案
是否可以在
onDestroy()
之后调用回调方法?
Is it possible for a callback method to be called after
onDestroy()
?
是的
让我们稍微更改一下有关将Runnable
发布到Handler
的示例代码.我还假设(根据您的描述)您可能在主线程中发布了多个Runnable
,因此在某些时候可能会有一个Runnable
队列,这使我在下面的实验中有所延迟:
Let's change a bit your sample code regarding posting a Runnable
to the Handler
. I also assume (according to your description) that you may have multiple Runnable
s posted to the main thread, so at some point there might be a queue of Runnable
s which brings me to a delay in the experiment below:
public void onClick(View view) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// This is the callback method
Log.d("TAG", "listenerNotified");
}
}, 3000);
}
现在按按钮b
,然后按返回按钮,您应该看到有问题的输出.
Now push the button b
, then press the back button and you should see the output in question.
Might it be the reason of your app crash?
很难不说就知道.我只想指出,在线程(在您的情况下为主线程)上实例化new Handler()
时,Handler
与该线程的Looper
消息队列相关联,发送并处理Runnable
和来自队列的消息.这些Runnable
和消息具有对目标Handler
的引用.即使Activity
的onDestroy()
方法不是析构函数",即,当该方法返回Activity
的实例时,也不会立即被杀死(
Might it be the reason of your app crash?
It's hard to say without seeing what you got. I'd just like to note that when new Handler()
is instantiated on a thread (the main thread in your case), the Handler
is associated with the Looper
's message queue of the thread, sending to and processing Runnable
s and messages from the queue. Those Runnable
s and messages have a reference to the target Handler
. Even though Activity
's onDestroy()
method isn't a "destructor", i.e. when the method returns the Activity
's instance won't be immediately killed (see), the memory cannot be GC-ed because of the implicit reference* to the Activity
. You'll be leaking until the Runnable
will be de-queued from the Looper
's message queue and processed.
更详细的解释可以在如何找到泄漏上下文:处理程序和内部类
*匿名内部类Runnable
的实例具有对匿名内部类View.OnClickListener
的实例的引用,而该实例又引用了Activity
实例.
* Instance of anonymous inner class Runnable
has a refers to an instance of anonymous inner class View.OnClickListener
that, in its turn, has a reference to the Activity
instance.
这篇关于是否可以在onDestroy之后调用回调方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!