はじめに
最近Android開発を触り始めました。
findViewByIdを使用する事でviewを取得できますが、調べてみると繰り返し処理の中でfindViewByIdを何回も繰り返す事は処理速度的にあまりよくないとのことだったので検証してみました。
なぜ処理速度的にあまりよくない?
findViewByIdはviewの階層の上から順に検索していくため、階層が深いほど処理時間がかかる。
例
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints">
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</FrameLayout>
</FrameLayout>
findViewByIdでTextViewを取得したい場合、一番上の階層から順にFrameLayout -> FrameLayout -> TextViewのように検索する?
検証
3パターン検証してみました。
検証1:FrameLayout 1階層
検証2:FrameLayout 10階層
検証3:FrameLayout 20階層
上記3パターンそれぞれ、FrameLayoutの最下層にTextViewを配置し、for文を使いTextViewを取得するfindViewByIdを100万回実行してみました。
認識があっていれば検証3、検証2、検証1の順で時間がかかるはずです。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("Debug Start", getNowDate().toString());
for (int index = 1; index <= 1000000; index++) {
TextView textview = (TextView) findViewById(R.id.text1);
textview.getText();
}
Log.d("Debug End", getNowDate().toString());
}
検証1
<?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">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints">
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</FrameLayout>
検証2
<?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">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints">
<!-- <FrameLayout...
<FrameLayout ...
<FrameLayout ...
のようにFrameLayoutを10階層作る -->
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<!-- </FrameLayout>
</FrameLayout>
</FrameLayout>
..... -->
</FrameLayout>
検証3は検証2と同様にFrameLayoutを20階層作りました。
結果
数回実行してみての平均処理時間
検証 | 処理時間 |
---|---|
検証1 | 0.13秒 |
検証2 | 0.24秒 |
検証3 | 0.39秒 |
となりました。想定通り階層が深いほど処理時間が伸びていく結果となりました。
まとめ
findViewByIdを使用する際は階層が深い場合は注意が必要。
Activity内で何度も使用する場合はメモリリークには気を付けてメンバ変数で宣言してしまった方が良さそうです。