Android GridViewのパフォーマンスチューニング(2/2)

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

前回はgetView()で遅い処理をしない事、ViewHolderを使う事、を紹介しました。

今回は更にチューニングが必要な場合に可能な対策を紹介します。

3.スクロール中に別スレッドでの処理をしない

別スレッドで処理している前提ですが、特に画像エンコード等GCの発生する可能性の高い処理はスクロール時には止めます。GCが発生すると数十msecフリーズしてスクロールに影響するためです。GridViewのonScrollStateChanged イベントで制御します。(decodeをqueueで管理するイメージです)

// GridViewのsetOnScrollListenerでデコードのタイミングを制御します。
gridView.setOnScrollListener(new OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView paramAbsListView, int scrollState) {
        switch (scrollState) {
        // スクロールしていない
        case OnScrollListener.SCROLL_STATE_IDLE:
            // decode処理をqueueに登録して開始する記述
            break;

        // スクロール
        case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
            // decodeのqueueをキャンセルする処理を記述
            break;

        // フリック
        case OnScrollListener.SCROLL_STATE_FLING:
            // decodeのqueueをキャンセルする処理を記述
            break;
        default:
        }
    }
}

これで、スクロール時にGCが発生して少しフリーズする現象が起きなくなりました。

4.Viewの数を減らす

それでも特に一つのグリッド内のViewの構成が複雑な場合に、まだ納得できるスムースさにならない場合があると思います。

LinerLayout、TextView、ImageView等のレイアウトを多数組み合わせた場合にViewの数に比例してパフォーマンスは悪化しているようです。そこで一つのViewを継承したカスタムViewで一つのGrid内(=getView1回)の描画を済ましてしまう作戦です。デメリットとしては便利なViewの機能が使えないことてすが、Grid内であまり複雑な動きや表示をすることはレアケースだと思います。

ですのでここは、カスタムビューでCanvasに思いきりdraw()しましょう。

// アダプタ。
public class PhotoArrayAdapter extends ArrayAdapter<Photo> {
	@Override
	public View getView(int position, View convertView, ViewGroup parent) {

			Photo photo = getItem(position);
			
			if(convertView == null){
				convertView = mLayoutInflater.inflate(mTextViewResourceId, null);
			}
			
			// カスタムビューに値を設定
			FastView fastView = (FastView)convertView;
			fastView.bitmap = bitmap; // decodeされたBitmap
			fastView.dateTime = photo.dateTime;
			fastView.height = photo.length;
			fastView.height = photo.width;
			fastView.invalidate();
	}
}
//カスタムView。
public class FastView extends View {

	public Bitmap bitmap;
	public String filePath;
	public String width;
	public String height;
	public String dateTime;

	public FastView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);

		Paint paint = new Paint();
		paint.setAntiAlias(true);
		
		// 画像、Exif情報をdraw
		canvas.drawBitmap(bitmap, 10, 10, paint);
		canvas.drawText(filePath, 200, 10, paint);
		canvas.drawText(width, 200, 40, paint);
		canvas.drawText(height, 200, 60, paint);
		canvas.drawText(dateTime, 200, 80, paint);
	}
}

これでかなりスムースになります。

結局、全部カスタムViewでdrawしちゃえば最速なのか?とも考えますが、よっぽど暇じゃない限りは便利な既存のViewをうまく使い、GridVewのように、パフォーマスが落ちやすい&カスタム効果高い場合のみ賢くカスタムViewにするのが良いかなと思います。

GridVew又はListViewで描画が減って瞬間移動するような時は是非参考にしてみて下さい。