s1m*_*m0n 5 java multithreading android android-lifecycle android-activity
在我的应用程序的最新版本中,一些用户遇到了我无法重现的崩溃.目前只有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");
}
}
Run Code Online (Sandbox Code Playgroud)
每次我通过首先点击Click me按钮然后再按下后退按钮listenerNotified来测试上述应用程序之前,都会打印到控制台onDestroy().
但我不确定我是否可以依赖这种行为.Android对上述场景有任何保证吗?我可以安全地假设我的命令Runnable总是会被执行,onDestroy()或者是否存在不会出现这种情况的情况?在我的真实应用程序中,当然会发生更多事情(比如发布到主线程的其他线程以及回调中发生的更多操作).但这个简单的片段似乎足以证明我的担忧.
是否所有可能(可能是由于其他线程的影响或发布到主线程的回调)我得到下面的调试输出?
D/TAG: onDestroy
D/TAG: listenerNotified
Run Code Online (Sandbox Code Playgroud)
我想知道这一点,因为可能的结果可以解释崩溃.
之后是否可以调用回调方法
onDestroy()?
是的。
让我们稍微更改一下有关将 a 发布Runnable到Handler. 我还假设(根据您的描述)您可能有多个Runnables 发布到主线程,因此在某些时候可能会有一个 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);
}
Run Code Online (Sandbox Code Playgroud)
现在按下按钮b,然后按下后退按钮,您应该会看到相关的输出。
Might it be the reason of your app crash?如果没有看到你得到的东西,很难说。我只是想指出,当在new Handler()线程(您的情况下是主线程)上实例化时,与线程的消息队列Handler相关联,发送到队列并处理队列中的消息和消息。这些s 和 messages 引用了目标。即使's方法不是“析构函数”,即当该方法返回's 实例时不会立即终止(请参阅),但由于对 的隐式引用*,内存无法被 GC 回收。您将发生泄漏,直到将从 的消息队列中出队并得到处理。LooperRunnableRunnableHandlerActivityonDestroy()ActivityActivityRunnableLooper
* 匿名内部类的实例Runnable有一个引用匿名内部类的实例View.OnClickListener,而该实例又具有对该Activity实例的引用。