前回の実験の続き

前回のコメントでImageView#setImageDrawable(null)すればbitmap#recycleは不要という指摘を頂いたので実験

実験6 recycleしない
実験6-2 実験6の状態で画面の向きを変更
実験7 実験5の状態で画面の向きを変更
実験8 実験5の状態でモンキーチックなことを人力で


手順
MainActivity>BitmapActivity>MainActivity>BitmapActivity>GC>jhat

ソースを以下のように変更

public class BitmapActivity extends Activity {
	private ImageView image;
	private Bitmap bitmap;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.recycle);
		image = (ImageView) findViewById(R.id.imageView1);
	}

	@Override
	protected void onResume() {
		super.onResume();
		bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.python_logo);
		image.setImageBitmap(bitmap);
	}

	@Override
	protected void onPause() {
		super.onPause();
		image.setImageDrawable(null);
		// bitmap.recycle();
		// bitmap = null;
	}

	public void onNextButtonClick(View v) {
		Intent intent = new Intent(this, NextActivity.class);
		startActivity(intent);
	}

}
結果


確かにActivityは1つしかない。なので、リークは起きない様子
画面を遷移したり、ホームに戻ったりしたが問題ない

実験6-2 BitmapActivity表示中に画面向き変更

別に意地悪したいわけではないが、画面を縦横に変化させてみた

結果


2つある

1個目

jikken6_3-01.png
これはフォアグランドで動いているやつの様子
別段問題はなさそう

2個目
こいつは回収されてないやつ。
興味深いのはInstance data members:のbitmapがnullになっていて、imageはまだいる

ImageViewを覗くとこうなっている

mDrawable (L) :
どうやらBitmapの回収はされている様子。ただし、Activityは回収されていない。何かしらが参照しているのか?

BitmapActivityに戻ってReferences to this object:を見てみる

ImageViewがActivityを参照しているだけでなく、その他のViewの参照も残っている

とりあえずもう一回GCしてみる

GC実行してjhatで覗くとこうなる

変わらず
その後画面を戻したりなどフォアグラウンドでない状態でも確認したがやはり回収されなかった

実験7 実験5の最終状態で画面の向き変更

ソースを以下のように戻す

public class BitmapActivity extends Activity {
	private ImageView image;
	private Bitmap bitmap;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.recycle);
		image = (ImageView) findViewById(R.id.imageView1);
	}

	@Override
	protected void onResume() {
		super.onResume();
		bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.python_logo);
		image.setImageBitmap(bitmap);
	}

	@Override
	protected void onPause() {
		super.onPause();
		image.setImageDrawable(null);
		 bitmap.recycle();
		 bitmap = null;
	}

	public void onNextButtonClick(View v) {
		Intent intent = new Intent(this, NextActivity.class);
		startActivity(intent);
	}

}
結果


Activityは1つしかない

実験8 実験5の状態で人力モンキー

何回も向きを変えたり画面遷移したりモンキー的な動作をする

結果


Activityは1つしかいない。
この結果よりやはりrecycleはした方がいいのではないかと思う

結論

前回の結論と変わらず。
ImageView#setImageDrawable(null)
Bitmap#recycle()
両方やったほうがよさげ

あと、今回はImageViewとの連携だったけど、ImageViewを使わないケースもあるのでrecycleはしといた方がよさげ

釈然としないこと

今回のケースではActivityはBitmapを参照しているが、BitmapはImageViewで使っている以外はどこからも参照されていない。
なのでImageViewがただしく破棄されればActivityもGC対象になり、自動的にBitmapもGCされるのではないか?と思う。
実験6-2の段階で上手にActivityの参照がなくなれば破棄されそうなんだよね。そうなると指摘どおりBitmap#recycleは必ずしも必要ではなくなる。

もしかして、これを

		bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.python_logo);

をこうすると、いけるのかな?

		bitmap = BitmapFactory.decodeResource(getApplicationContext().getResources(), R.drawable.python_logo);

とりあえず、実験はここまでにする。少しばかりの達成感と、二度とやりたくない気持ちを込めて終了。
shisei_ssiさん。コメントありがとうございました。