在我的应用程序的最新版本中,一些用户遇到了我无法重现的崩溃。目前仅Samsung
设备运行Lollipop
遇到这个问题,但这可能只是巧合。
在分析了堆栈跟踪和相关代码之后,我想我可能已经找到了罪魁祸首。为了测试我的假设,我将代码简化为下面的代码片段:
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按钮,然后返回按钮,listenerNotified
之前打印到控制台onDestroy()
.
然而我不确定我是否可以依赖这种行为。做Android
对上述情况有何保证?我可以放心地假设我的Runnable
总是会在之前执行onDestroy()
还是有一种情况不会出现这种情况?在我的真实应用程序中,当然还会发生更多事情(例如其他线程发布到主线程以及回调中发生更多操作)。但这个简单的片段似乎足以证明我的担忧。
我是否有可能得到下面的调试输出(可能是由于其他线程或发布到主线程的回调的影响)?
D/TAG: onDestroy
D/TAG: listenerNotified
我想知道这一点,因为如果有可能出现这样的结果就可以解释这次事故。
之后是否可以调用回调方法onDestroy()
?
Yes.
让我们稍微更改一下有关发布的示例代码Runnable
to the Handler
。我还假设(根据您的描述)您可能有多个Runnable
s 发布到主线程,因此在某些时候可能会有一个队列Runnable
这让我在下面的实验中遇到了延迟:
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
,然后按后退按钮,您应该会看到有问题的输出。
Might it be the reason of your app crash?
如果没有看到你得到的东西,很难说。我只是想指出,当new Handler()
在线程(您的情况下的主线程)上实例化,Handler
与Looper
线程的消息队列,发送并处理Runnable
s 和来自队列的消息。那些Runnable
s 和 messages 都有对目标的引用Handler
。虽然Activity
's onDestroy()
方法不是“析构函数”,即当该方法返回Activity
的实例不会立即被杀死(see),由于隐式引用*,内存无法被 GC 回收Activity
。你会泄漏直到Runnable
将从队列中出队Looper
的消息队列并进行处理。
更详细的解释可以在如何泄漏上下文:处理程序和内部类
* 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.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)