この記事は
AndroidViewでViewを非表示にする場合、Viewに対してView.GONE
かView.INVISIBLE
を適用させると思います。(それぞれ違いについては他の記事に詳しく書いてあるのでそちらを参照してください)
しかし、APIの結果や時間の経過によってViewを表示・非表示させたい時がある場合はどちらを適用させたらいいか分からない場合があると思うのでPerfettoを使用してそれぞれの再描画パフォーマンスについて比較していきます
結論
Viewの表示・非表示が繰り返されそうな場合はView.INVISIBLE
を使用しましょう
検証
使用したツール
Perfetto
ADBを介してAndroidデバイスからパフォーマンス情報を収集するためのツールです。GUI上で簡単に可視化出来るためこちらを使用しました
測定方法
TextViewを表示させてから2秒後に非表示にします、それから2秒後に再描画させたタイミングで測定しています
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
CoroutineScope(Dispatchers.Main).launch {
delay(2000)
binding.textView.visibility = View.INVISIBLE or View.GONE
delay(2000)
binding.textView.visibility = View.VISIBLE // ← このタイミングで測定
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
結果
View.INVISIBLE
の場合であれば即座に描画が開始されますが、一方のView.GONE
の場合であれば描画が開始されるまでにmeasureとlayoutの処理が走っており、描画までに多少時間がかかってしまいます。描画開始から描画終了までの時間(Wall duration)も二倍以上の差が出ています。
おそらくですが、View.GONE
の場合レイアウト自体が変更になるため、再描画の際にレイアウトの再構築も行わないといけないためなのかな〜と思われます
View.GONE
Name | Wall duration (ms) | Avg Wall duration (ms) |
---|---|---|
Total | 35.199789 | |
Choreographer#doFrame 533822 | 6.979583 | 6.979583 |
traversal | 6.932708 | 6.932708 |
draw | 5.298625 | 5.298625 |
postAndWait | 4.433833 | 4.433833 |
DrawFrames 533822 | 4.400208 | 4.400208 |
Drawing 0.00 0.00 1080.00 2220.00 | 4.281625 | 4.281625 |
measure | 1.093 | 1.093 |
Record View#draw() | 0.779208 | 0.779208 |
flush commands | 0.360333 | 0.360333 |
layout | 0.275416 | 0.275416 |
View.INVISIBLE
Name | Wall duration (ms) | Avg Wall duration (ms) |
---|---|---|
Total | 14.539373 | |
DrawFrames 521826 | 2.568709 | 2.568709 |
Drawing 0.00 0.00 1080.00 2220.00 | 2.533916 | 2.533916 |
Choreographer#doFrame 521826 | 2.370708 | 2.370708 |
traversal | 2.343959 | 2.343959 |
draw | 2.263 | 2.263 |
postAndWait | 2.149042 | 2.149042 |
flush commands | 0.099833 | 0.099833 |
Record View#draw() | 0.076166 | 0.076166 |
補足
念の為測定にあたっては、前後の影響を受けさせないために複数回測定しましたがどれも同じような結果でした
Wall duration (Total)
View.INVISIBLE
の場合(14.5ms)→View.INVISIBLE
の場合(15.4ms)→View.GONE
の場合(20.9ms)→View.GONE
の場合(35.9ms)→View.INVISIBLE
の場合(14.6ms)→View.INVISIBLE
の場合(17.4ms)→View.GONE
の場合(23.7ms)→View.GONE
の場合(35.2ms)
リリースビルドとの比較
念のためリリースビルドでも比較してみましたが、目立った変化はありませんでした
View.GONE
Name | Wall duration (ms) | Avg Wall duration (ms) |
---|---|---|
Total | 46.361167 | |
Choreographer#doFrame 710656 | 7.863083 | 7.863083 |
traversal | 7.828792 | 7.828792 |
DrawFrames 710656 | 7.810667 | 7.810667 |
Drawing 0.00 0.00 1080.00 2220.00 | 7.647542 | 7.647542 |
... | ... | ... |
View.INVISIBLE
Name | Wall duration (ms) | Avg Wall duration (ms) |
---|---|---|
Total | 12.10375 | |
DrawFrames 707407 | 3.132167 | 3.132167 |
Drawing 0.00 0.00 1080.00 2220.00 | 3.07225 | 3.07225 |
Choreographer#doFrame 707407 | 1.400542 | 1.400542 |
traversal | 1.386583 | 1.386583 |
... | ... | ... |