Androidアプリのパフォーマンス 改善②(RecyclerView.Adapter)


この記事では、Androidアプリのパフォーマンス改善のための、方法について記載しています。

改善対象

リストなどを表示する場合、RecyclerViewを使うことがあると思います。
RecyclerViewはとても便利なクラスですが、パフォーマンスには注意が必要です。

計測

下記のRecyclerViewを使ったカレンダーのパフォーマンスをSystraceを使って計測しました。

すると、AdapterのonCreateViewHolderのinflateに時間がかかっている(下記の場合は、15.506ms)ことがわかりました。

onCreateViewHolderはRecyclerViewのitemの数だけ呼ばれるので、onCreateViewHolderに時間がかかるとパフォーマンスにかなり影響があります。

改善方法

改善には、RecyclerViewのitem生成にinflateを使用せず、Viewを生成(CustomView)する方法があります。

     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DateAdapterHolder {
-        val view = inflater.inflate(R.layout.calendar_item, parent, false)
-        return DateAdapterHolder(view)
+        return DateAdapterHolder(
+                CalenderItemView(parent.context).apply {
+                    layoutParams = LinearLayout.LayoutParams(parent.width / 7, ITEM_HEIGHT.toInt())
+                }
+        )
     }
CalenderItemView.kt
class CalenderItemView @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyle: Int = 0
) : LinearLayout(context, attrs, defStyle) {
    companion object {
        private val TEXT_SIZE = 20f.sp
        private val MARGIN_SIZE = 5f.sp
        val ITEM_HEIGHT = TEXT_SIZE + MARGIN_SIZE * 2
        private val textPaint = Paint().apply {
            textSize = TEXT_SIZE
        }
    }

    var date: String = ""
    var color: Int = Color.BLACK

    init {
        gravity = Gravity.RIGHT
        setBackgroundColor(Color.WHITE)
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        textPaint.color = color
        canvas?.drawText(
                date,
                if (date.length == 1) TEXT_SIZE / 2 else 0f.sp,
                TEXT_SIZE + MARGIN_SIZE,
                textPaint
        )
    }
}

この修正により、onCreateViewHolderの時間(Systraceで計測)は1/10(平均6.638msから0.735ms)に改善されました。

実装の詳細は下記を参照してください。
https://github.com/yoshihiro-kato/android-samples/tree/4e8ca216a71bf4f147ff854e4a8872b889639ea3/KotlinSampleApplication

補足

CustomViewにするとCanvasにテキストやBitmapを直接描画することになるので、TextViewのellipsize等が使えなくなります。