【Jetpack Compose】「Layout Inspector Recomposition counts」で re-compose 回数を確認する

Jetpack Compose を使っていると、

いつ、どの composable が、 compose されているか、

パフォーマンスが重ければ重いほど気になります。

確認してみましょう。

 

Layout Inspector

すごく便利そうな AndroidStudio の機能です。

【 Jetpack Compose】Layout Inspector Recomposition counts

👉 Compose のパフォーマンス  |  Jetpack Compose  |  Android Developers hatena-bookmark


[Tools]

  ↓

[Layout Inspector]

 

利用条件

端末側で設定が必要です。


表示属性検査を有効にする

【 Jetpack Compose】Layout Inspector Recomposition counts

👉 Compose のツール  |  Jetpack Compose  |  Android Developers hatena-bookmark

R8 などは OFFにする。


debug {
  minifyEnabled false // for layout inspector
  proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}

あと、一番ネックになるのがこれ。

This is only available in Electric Eel at the moment:

"For even more cutting edge features, you can take a sneak peek at the Android Studio Electric Eel release in the Canary channel [...] These features will be promoted to more stable channels once we have your feedback and make improvements, so please try them out."

👉 android - Jetpack Compose: The layout inspector is not showing the menu for recomposition counts - Stack Overflow hatena-bookmark


Android Studio Electric Eel release in the Canary channel

今はまだ、非Statble な「Android Studio Electric Eel」でしか使えないようです。

JetBrains の「Toolbox」を使っていれば問題ありません。

JetBrains Toolbox で Android Studio の Stable/Beta/Canary が同時に管理できる?

使ってない人は、すぐインストールしておきましょう。

👉 JetBrains Toolbox で Android Studio の Stable/Beta/Canary が同時に管理できる? hatena-bookmark

 

結果

左下に Layout Inspector が開いたら以下。


[Component Tree]

  ↓

[View Option]

  ↓

[Show Recomposition counts]

compose counts

ヘビーな LazyVerticalGrid でやってみました。

re-compose されると、その部分が赤く変色します。



しかしこれ、

重すぎやせんか、ツールとして。

しかも、よく落ちる。

今後、期待しています。

👉 「Compose Compiler Reports」 recompose される条件とタイミングと範囲を知りたい hatena-bookmark
👉 【Jetpack Compose】LazyVerticalGrid - Profile GPU Rendering / Profile HWUI rendering - YouTube hatena-bookmark


【AndroidStudio】DesignTools の Preview デフォルトを「Split」→「Code」にする

JetPack Compose を触りながら、

コードの編集をしてファイルを切り替えていると、

デフォルトで右側に「Preview」画面が表示されますね。

なんかうざい。

Default Split

デフォルトは 「Split」 でなく 「Code」 でいいのに。

デフォルトを「Code」にしておきましょう。


[Preferences]

  ↓

[Editor]

  ↓

[Design Tools]

最近、この Preview画面、

ずっと Refreshing 状態のときがあったり、

デザインのためのビルドされるのも意図したときだけにしたかったので。


【Jetpack Compose】TextField の フォーカス と IME 開閉 と カーソル位置

 

TextField を使うときのあれこれ、Jetpack Compose ではどう書くのか。

【Jetpack Compose】TextField の フォーカス と IME 開閉 と カーソル位置

 

キーボードの開閉

それらしいクラスやメソッドがあります。フォーカスが当たっていれば使えます。


val keyboardController = LocalSoftwareKeyboardController.current
keyboardController?.show()
keyboardController?.hide()

フォーカスを当てたり外したりすることのみでも、IMEを開閉できるので今回は無視します。

 

フォーカスを当てる

FocusRequester を使います。


val focusRequester = remember { FocusRequester() }

focusRequester を TextFiled に仕込みます。


TextField(
  modifier = Modifier.focusRequester(focusRequester)
)

それを Button クリックでフォーカスします。


Button(
  onClick = { focusRequester.requestFocus() }
) {
  Text("SHOW IME")
}

フォーカスと同時にIMEも開きます。

compose 時に当てたいときは、


LaunchedEffect(Unit) {
  focusRequester.requestFocus()
}

 

フォーカスを外す

同様に、FocusRequester でやれると思ったら、できません。

LocalFocusManager を使います。


val focusManager = LocalFocusManager.current

フォーカスを外してくれます。

同様に、ボタンに仕込みます。


Button(
  onClick = { focusManager.clearFocus() }
) {
  Text("HIDE IME")
}

これも、フォーカスを外すと同時にIMEが閉じます。

 

カーソルの位置

文字の入った TextField にフォーカスしてIMEが開いたときは、編集です。

文字の最後尾にカーソルがあったほうがいい気がします。

TextFieldValue を使います。


TextFieldValue(
  text = text,
  selection = TextRange(text.length)
)

selection がカーソルの位置です。

text の長さを数えて置きます。日本語でもいけます。

 

まとめ

以下で検証してみました。


@Composable
fun SampleScreen() {

  var text by remember { mutableStateOf("あいうえお") }

  val focusManager = LocalFocusManager.current
  val focusRequester = remember { FocusRequester() }

  Column(
    Modifier.fillMaxSize(),
    Arrangement.Center,
    Alignment.CenterHorizontally
  ) {

    Text(text)
    Spacer(Modifier.height(16.dp))
    Row {
      Button(
        onClick = { focusRequester.requestFocus() }
      ) {
        Text("SHOW IME")
      }
      Spacer(Modifier.width(24.dp))
      Button(
        onClick = { focusManager.clearFocus() }
      ) {
        Text("HIDE IME")
      }
    }
    Spacer(Modifier.height(16.dp))
    CustomTextField(
      text = text,
      focusRequester = focusRequester,
      onChange = { changed ->
        text = changed
      }
    )

  }
}

@Composable
fun CustomTextField(
  text: String,
  focusRequester: FocusRequester,
  onChange: (String) -> Unit
) {

  var textFieldValue by remember {
    mutableStateOf(
      TextFieldValue(
        text = text,
        selection = TextRange(text.length)
      )
    )
  }

  TextField(
    value = textFieldValue,
    onValueChange = { changed ->
      textFieldValue = changed
      onChange(changed.text)
    },
    modifier = Modifier.focusRequester(focusRequester)
  )

}

【Jetpack Compose】TextField の フォーカス と IME 開閉 と カーソル位置

Compose の SideEffect や coroutineScope など、非同期処理系は悩ましくなりそうです。