据我所知,当我旋转屏幕时,活动被破坏并重新创建。在以下情况下,似乎并非总是如此。所以问题是:它真的被破坏了吗?我是出于某种原因泄漏内存吗?如果未销毁它,它是否与新创建的活动在同一线程上运行?
该方案是一个“垂直”活动,它将启动IntentService,该服务需要5秒钟才能完成,并使用ResultReceiver将结果发送回去。在这5秒钟内,屏幕旋转,并且创建了一个新的“水平”活动。结果返回到“垂直”活动,而不是新的“水平”活动。那么,“垂直”活动不会被破坏吗?
我创建了一个项目来演示这一点。代码来了。
首先,带有活动布局的xml。只需两个按钮。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show value of variable" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start IntentService" />
</LinearLayout>
之后,我们的IntentService
public class SomeService extends IntentService {
public SomeService(){
super("SomeService");
}
@Override
protected void onHandleIntent(Intent intent) {
ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver");
long t0, t1;
t0 = System.currentTimeMillis();
do {
t1 = System.currentTimeMillis();
} while (t1-t0 < 5000);
receiver.send(0, null);
}
}
最后是活动
public class TestActivityDestructionActivity extends Activity {
private int mTestVar = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (savedInstanceState != null){
mTestVar = savedInstanceState.getInt("tv");
}
mTestVar++;
Button b1 = (Button) findViewById(R.id.button1);
b1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(TestActivityDestructionActivity.this, "Value: " + mTestVar, Toast.LENGTH_SHORT).show();
}
});
Button b2 = (Button) findViewById(R.id.button2);
b2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(TestActivityDestructionActivity.this, SomeService.class);
intent.putExtra("receiver", new SomeReceiver(new Handler()));
startService(intent);
Toast.makeText(TestActivityDestructionActivity.this, "IntentService started", Toast.LENGTH_SHORT).show();
}
});
}
private class SomeReceiver extends ResultReceiver{
public SomeReceiver(Handler handler) {
super(handler);
}
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
Toast.makeText(TestActivityDestructionActivity.this, "Receiver value: " + mTestVar, Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tv", mTestVar);
}
}
当活动首次启动时,mTestVar为0,而onCreate则增加为1。活动被销毁时,它将保存该值。下一个活动将其加载并将其增加到2,依此类推。
请按照下列步骤操作:
单击Button1:mTestVar是1
单击Button2:服务开始
在5秒钟之前旋转屏幕
单击Button1:mTestVar为2(调用了onCreate)
等待5秒钟:mTestVar仍然显示为1
据我所知,这意味着第一个活动没有被破坏。我想念什么吗?
谢谢!
编辑
在看到了这个问题的答案之后,我使用了MAT和堆转储,发现第一个活动永远不会被垃圾收集,即使该服务早已消失并且已被垃圾收集,并且不再引用该活动了。我不知道为什么
但是,如果从未创建接收方并且从未将接收方传递给服务,则不会发生内存泄漏。第一次活动已按预期被破坏。无论如何,没有理由不这样做。
最佳答案
通过调试器在代码中使用断点来运行它,并在ResultReceiver中检查“ this”的ID。它保留了指向此先前活动的本地“ this”副本,其中int mTestVar ==1。当前活动Activity是一个完全不同的对象,它是mTestVar == 2的副本。这是内存泄漏。
为了更简洁地回答您的问题:Android“销毁了”您的活动,但是您在回调中保留了对活动的引用,以防止对其进行垃圾回收。如果您希望某项内容在多个活动中“存在”,则应使用服务来存储该状态(请记住,服务不是单独的线程,不应像一个线程那样使用)。
附带说明:检查变量和通用记录时,最好使用Log.v / e / i等。您可以在命令行使用adb logcat mytag:V *:S过滤它们,或使用eclipse中内置的logcat。