私の知る限り、画面を回転させると、アクティビティが破棄されて再作成されます。次のシナリオでは、常にそうであるとは限りません。問題は、それは本当に破壊されているのかということです。何らかの理由でメモリリークしていますか?破棄されていない場合、新しく作成されたアクティビティと同じスレッドで実行されますか?
このシナリオは、IntentService を開始する「垂直」アクティビティです。サービスが完了するまでに 5 秒かかり、ResultReceiver を使用して結果を返します。この 5 秒間で画面が回転し、新しい「水平」アクティビティが作成されます。結果は、新しい「水平」アクティビティではなく、「垂直」アクティビティに戻ります。それで、「垂直」活動は破壊されませんか?
これを実証するプロジェクトを作成しました。これがコードです。
まず、アクティビティ レイアウトを含む xml。ボタンはたったの2つ。
<?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 とヒープ ダンプを使用したところ、サービスがなくなってガベージ コレクションが行われ、アクティビティへの参照がなくなったにもかかわらず、最初のアクティビティがガベージ コレクションではないことがわかりました。どうしてか分かりません。
ただし、レシーバーが作成されず、サービスに渡されない場合、メモリ リークは発生しません。最初のアクティビティは期待どおりに破棄されます。とにかく、そうしない理由はありません。