Android GridViewのパフォーマンスチューニング(2/2)
前回は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で描画が減って瞬間移動するような時は是非参考にしてみて下さい。