Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compose兼容 #65

Closed
Iridescentangle opened this issue Mar 12, 2022 · 8 comments
Closed

Compose兼容 #65

Iridescentangle opened this issue Mar 12, 2022 · 8 comments

Comments

@Iridescentangle
Copy link

有考虑兼容Compose嘛(╹▽╹)尝试在Scene中嵌入ComposeView报错

java.lang.IllegalStateException: ViewTreeLifecycleOwner not found from com.bytedance.scene.view.NavigationFrameLayout{d382d6a V.E...... ......ID 0,0-1080,2026 #7f08035d app:id/navigation_scene_content}
        at androidx.compose.ui.platform.WindowRecomposer_androidKt.createLifecycleAwareWindowRecomposer(WindowRecomposer.android.kt:275)
        at androidx.compose.ui.platform.WindowRecomposer_androidKt.createLifecycleAwareWindowRecomposer$default(WindowRecomposer.android.kt:259)
        at androidx.compose.ui.platform.WindowRecomposerFactory$Companion$LifecycleAware$1.createRecomposer(WindowRecomposer.android.kt:103)
        at androidx.compose.ui.platform.WindowRecomposerPolicy.createAndInstallWindowRecomposer$ui_release(WindowRecomposer.android.kt:159)
        at androidx.compose.ui.platform.WindowRecomposer_androidKt.getWindowRecomposer(WindowRecomposer.android.kt:234)
        at androidx.compose.ui.platform.AbstractComposeView.resolveParentCompositionContext(ComposeView.android.kt:244)
        at androidx.compose.ui.platform.AbstractComposeView.ensureCompositionCreated(ComposeView.android.kt:251)
        at androidx.compose.ui.platform.AbstractComposeView.onAttachedToWindow(ComposeView.android.kt:283)
        at android.view.View.dispatchAttachedToWindow(View.java:20123)
        at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3430)
        at android.view.ViewGroup.addViewInner(ViewGroup.java:5193)
        at android.view.ViewGroup.addView(ViewGroup.java:4979)
        at android.view.ViewGroup.addView(ViewGroup.java:4919)
        at android.view.ViewGroup.addView(ViewGroup.java:4892)
        at com.bytedance.scene.navigation.NavigationSceneManager.moveState(NavigationSceneManager.java:413)
        at com.bytedance.scene.navigation.NavigationSceneManager.access$1800(NavigationSceneManager.java:92)
        at com.bytedance.scene.navigation.NavigationSceneManager$PushOptionOperation.execute(NavigationSceneManager.java:900)
        at com.bytedance.scene.navigation.NavigationSceneManager.executePendingOperation(NavigationSceneManager.java:301)
        at com.bytedance.scene.navigation.NavigationScene.dispatchActivityCreated(NavigationScene.java:584)
        at com.bytedance.scene.group.GroupSceneManager.moveState(GroupSceneManager.java:969)
        at com.bytedance.scene.group.GroupSceneManager.moveState(GroupSceneManager.java:964)
        at com.bytedance.scene.group.GroupSceneManager.access$1000(GroupSceneManager.java:208)
        at com.bytedance.scene.group.GroupSceneManager$MoveStateOperation.execute(GroupSceneManager.java:641)
        at com.bytedance.scene.group.GroupSceneManager.executeOperation(GroupSceneManager.java:241)
        at com.bytedance.scene.group.GroupSceneManager.add(GroupSceneManager.java:395)
        at com.bytedance.scene.group.GroupScene.add(GroupScene.java:197)
        at com.bytedance.scene.group.GroupScene.add(GroupScene.java:142)
@qii
Copy link
Member

qii commented Mar 16, 2022

疑,你是怎么使用的,Compose 这个东西不是理论上可以内嵌到任何的 ViewGroup 里面吗?

@Iridescentangle
Copy link
Author

https://developer.android.google.cn/jetpack/compose/interop/adding#reuse-view

假设我们要在应用中将用户问候文本迁移到 Jetpack Compose。我们可以在 XML 布局中添加以下内容:
为了将其迁移到 Compose,我们可以将 View 替换为保留了相同布局参数和 id 的 ComposeView
然后,在使用了该 XML 布局的 Activity 或 Fragment 中,我们可以获取 ComposeView,并调用 setContent 方法,以向其中添加 Compose 内容:

我是按照这种方式来做的

class ComposeScene : Scene() {
    private lateinit var composeView : ComposeView
    override fun onCreateView(p0: LayoutInflater, p1: ViewGroup, p2: Bundle?): View {
        composeView = ComposeView(requireSceneContext())
        return composeView
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        composeView.setContent {
            CardTheme {
                ProvideWindowInsets {
                    val systemUiController = rememberSystemUiController()
                    val darkIcons = MaterialTheme.colors.isLight
                    SideEffect {
                        systemUiController.setSystemBarsColor(Color.Transparent, darkIcons = darkIcons)
                    }
                    val navController = rememberNavController()
//                    val navigationActions = remember(navController){
//
//                    }
                    Greeting()
                }
            }
        }
    }
    @Composable
    private fun Greeting() {
       Text(
           text = "我是测试文字",
           modifier = Modifier.padding(horizontal = 10.dp, vertical = 5.dp)
       )
    }
}

@qii
Copy link
Member

qii commented Mar 18, 2022

在你的首页的 Activity 的 onCreate 里面补充这段代码

        ViewTreeLifecycleOwner.set(window.decorView, this)
        ViewTreeViewModelStoreOwner.set(window.decorView, this)
        ViewTreeSavedStateRegistryOwner.set(window.decorView, this)

@qii
Copy link
Member

qii commented Mar 18, 2022

头疼啊,公司内部的 androidx 版本普通很旧,所以这个框架也不好直接升级 androidx 的依赖

@qii
Copy link
Member

qii commented Mar 18, 2022

还有一种做法,我感觉这种更合适

import android.view.View
import androidx.compose.runtime.MonotonicFrameClock
import androidx.compose.runtime.PausableMonotonicFrameClock
import androidx.compose.runtime.Recomposer
import androidx.compose.ui.platform.AndroidUiDispatcher
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.bytedance.scene.Scene
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.launch
import kotlin.coroutines.EmptyCoroutineContext

  fun Scene.createLifecycleAwareViewTreeRecomposer(): Recomposer {
    val currentThreadContext = AndroidUiDispatcher.CurrentThread
    val pausableClock = currentThreadContext[MonotonicFrameClock]?.let {
        PausableMonotonicFrameClock(it).apply { pause() }
    }
    val contextWithClock = currentThreadContext + (pausableClock ?: EmptyCoroutineContext)
    val recomposer = Recomposer(contextWithClock)
    val runRecomposeScope = CoroutineScope(contextWithClock)
    val viewTreeLifecycleOwner = this
    // Removing the view holding the ViewTreeRecomposer means we may never be reattached again.
    // Since this factory function is used to create a new recomposer for each invocation and
    // doesn't reuse a single instance like other factories might, shut it down whenever it
    // becomes detached. This can easily happen as part of setting a new content view.
    this.view.addOnAttachStateChangeListener(
        object : View.OnAttachStateChangeListener {
            override fun onViewAttachedToWindow(v: View?) {}
            override fun onViewDetachedFromWindow(v: View?) {
                this@createLifecycleAwareViewTreeRecomposer.view.removeOnAttachStateChangeListener(this)
                recomposer.cancel()
            }
        }
    )
    viewTreeLifecycleOwner.lifecycle.addObserver(
        object : LifecycleEventObserver {
            override fun onStateChanged(lifecycleOwner: LifecycleOwner, event: Lifecycle.Event) {
                val self = this
                when (event) {
                    Lifecycle.Event.ON_CREATE ->
                        // Undispatched launch since we've configured this scope
                        // to be on the UI thread
                        runRecomposeScope.launch(start = CoroutineStart.UNDISPATCHED) {
                            try {
                                recomposer.runRecomposeAndApplyChanges()
                            } finally {
                                // If runRecomposeAndApplyChanges returns or this coroutine is
                                // cancelled it means we no longer care about this lifecycle.
                                // Clean up the dangling references tied to this observer.
                                lifecycleOwner.lifecycle.removeObserver(self)
                            }
                        }
                    Lifecycle.Event.ON_START -> pausableClock?.resume()
                    Lifecycle.Event.ON_STOP -> pausableClock?.pause()
                    Lifecycle.Event.ON_DESTROY -> {
                        recomposer.cancel()
                    }
                    Lifecycle.Event.ON_PAUSE -> {
                        // Nothing
                    }
                    Lifecycle.Event.ON_RESUME -> {
                        // Nothing
                    }
                    Lifecycle.Event.ON_ANY -> {
                        // Nothing
                    }
                }
            }
        }
    )
    return recomposer
}

然后你的 Scene,补充 composeView.setParentCompositionContext(createLifecycleAwareViewTreeRecomposer())

class ComposeScene : Scene() {
     private lateinit var composeView : ComposeView
    override fun onCreateView(p0: LayoutInflater, p1: ViewGroup, p2: Bundle?): View {
        composeView = ComposeView(requireSceneContext())
        return composeView
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        ViewTreeLifecycleOwner.set(this.view, this)
        ViewTreeViewModelStoreOwner.set(this.view, this)
        ViewTreeSavedStateRegistryOwner.set(this.view, fragmentActivity())

        composeView.setParentCompositionContext(createLifecycleAwareViewTreeRecomposer())
        composeView.setContent {
            CardTheme {
                ProvideWindowInsets {
                    val systemUiController = rememberSystemUiController()
                    val darkIcons = MaterialTheme.colors.isLight
                    SideEffect {
                        systemUiController.setSystemBarsColor(Color.Transparent, darkIcons = darkIcons)
                    }
                    val navController = rememberNavController()
//                    val navigationActions = remember(navController){
//
//                    }
                    Greeting()
                }
            }
        }
    }
    @Composable
    private fun Greeting() {
       Text(
           text = "我是测试文字",
           modifier = Modifier.padding(horizontal = 10.dp, vertical = 5.dp)
       )
    }
}

@qii
Copy link
Member

qii commented Mar 18, 2022

参考 https://github.com/bytedance/scene/blob/samples/compose/demo/src/main/java/com/bytedance/scenedemo/ComposeSamples.kt

@Iridescentangle
Copy link
Author

好的...我试一哈,多谢大佬指点ღ( ´・ᴗ・` )

@Iridescentangle
Copy link
Author

@qii 是可以的,多谢!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants