たくさんの自由帳

BottomSheetDialogFragmentとかDialogでComposeViewが使えない

投稿日 : | 0 日前

文字数(だいたい) : 4828

alpha 12から直ってない
beta02で修正されました。更新手順は、
app/build.gradleのKotlinバージョン、Composeのバージョンを以下のように変更し、

// Compose関係
composeOptions {
    kotlinCompilerVersion '1.4.31'
    kotlinCompilerExtensionVersion '1.0.0-beta02'
}

Composeのバージョンを上げて、
FragmentAppCompatのバージョンを1.3以上にすればこの問題は修正できます。

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation "androidx.compose.ui:ui:1.0.0-beta02"
    // Tooling support (Previews, etc.)
    implementation "androidx.compose.ui:ui-tooling:1.0.0-beta02"
    // Foundation (Border, Background, Box, Image, Scroll, shapes, animations, etc.)
    implementation "androidx.compose.foundation:foundation:1.0.0-beta02"
    // Material Design
    implementation "androidx.compose.material:material:1.0.0-beta02"
    // Integration with observables
    implementation "androidx.compose.runtime:runtime-livedata:1.0.0-beta02"
    // LayoutInspector
    implementation "androidx.compose.ui:ui-tooling:1.0.0-beta02"

    // fragment
    implementation 'androidx.fragment:fragment-ktx:1.3.1'

    // appcompat
    implementation 'androidx.appcompat:appcompat:1.3.0-beta01'

}

本題

BottomSheetDialogFragmentonCreateViewの返り値としてComposeView()を使うとエラーが出る問題

java.lang.IllegalStateException: ViewTreeLifecycleOwner not found from DecorView@b98b3fc[MainActivity]

環境

namevalue
Compose1.0.0 Beta 1

なんで?

ViewTreeLifecycleOwnerっていうViewからActivity/Fragmentのライフライクルを取得できるやつがあるんですけど、
親Viewを指定してViewTreeLifecycleOwner.get()を呼ぶとなぜかnullが返ってくる

解決方法

お好きな方をどうぞ

  • ViewTreeLifecycleOwner(とRecomposer)を指定する
  • androidx.fragmentをスナップショット版にする

ViewTreeLifecycleOwnerを指定する

Composeで使ってるRecomposerを作るのにViewTreeLifecycleOwnerが必要だった模様。
というわけでRecomposerを作って渡してあげる必要があります

ViewTreeLifecycleOwner.set()の第二引数はActivityの場合はActivityを(this)、
Fragmentの場合はviewLifecycleOwnerを渡してあげてください

class BottomFragmentCompose : BottomSheetDialogFragment() {

    @InternalComposeUiApi
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return ComposeView(requireContext()).apply {

            ViewTreeLifecycleOwner.set(this, viewLifecycleOwner)
            val newRecomposer = AtomicReference(WindowRecomposerFactory.LifecycleAware).get().createRecomposer(rootView)
            compositionContext = newRecomposer

            setContent {
                Text(
                    text = "BottomSheetDialogFragment + ComposeView",
                    modifier = Modifier.padding(10.dp)
                )
            }
        }
    }

}

DialogComposeViewを使う場合はViewTreeSavedStateRegistryOwnerの指定も必要かも

@InternalComposeUiApi
private fun showDialog() {
    Dialog(this).apply {
        setContentView(ComposeView(context).apply {
            ViewTreeLifecycleOwner.set(this, this@MainActivity)
            ViewTreeSavedStateRegistryOwner.set(this, this@MainActivity)
            val newRecomposer = AtomicReference(WindowRecomposerFactory.LifecycleAware).get().createRecomposer(this)
            compositionContext = newRecomposer
            setContent {
                Text(
                    text = "Dialog + ComposeView",
                    modifier = Modifier.padding(10.dp)
                )
            }
        })
    }.show()
}

Fragmentをスナップショット版にする

ついさっき知ったんですけど、build.gradleからallprojectsが消滅してた。(gradleが6.8になった影響?)
代替として、settings.gradledependencyResolutionManagementが追加された模様

allprojectがある場合

allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://androidx.dev/snapshots/builds/7172350/artifacts/repository' } // これを書き足す
    }
}

あとはappフォルダにあるbuild.gradleを開いて、androidx.fragmentをアップデートします

dependencies {
    implementation "androidx.fragment:fragment:1.4.0-SNAPSHOT"
}

dependencyResolutionManagementの場合

settings.gradleを開いて書き足す

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        jcenter() // Warning: this repository is going to shut down soon
        maven { url 'https://androidx.dev/snapshots/builds/7172350/artifacts/repository' }
    }
}

あとはappフォルダにあるbuild.gradleを開いて、androidx.fragmentをアップデートします

dependencies {
    implementation "androidx.fragment:fragment:1.4.0-SNAPSHOT"
}

おわりに

dependencyResolutionManagement ってなに

あとソースコード置いておきます

https://github.com/takusan23/BottomFragmentComposeView

参考にしました

https://issuetracker.google.com/issues/180691023