この記事では、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())
+ }
+ )
}
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等が使えなくなります。