JetPack组成:查看Interop迁移策略的用例
#kotlin #android #mobile #组成

方法

最近,我们有机会为我们正在开发的SDK重新设计示例应用程序。我们只是重新设计一个屏幕(主页),因此我们决定在应用程序中介绍Jetpack Compose

基于我们阅读的内容,大多数迁移或查看Interop帖子都是关于将Fragmentsfragment navigation保持原样,并将片段的内容移动到ComposeView中。实际上,official docs also mention that strategy.

为此,我们仍然必须触摸应用程序中的其他片段,而不仅仅是主页。因此,感觉比我们打算做的更多。最重要的是,示例应用程序广泛使用PreferenceFragmentCompat用于各种设置屏幕。要将其内容移至ComposeView,我们必须从头开始重新创建一种首选项屏幕,因为撰写没有直接替换PreferenceFragment

因此,我们决定采用Fragments in Compose方法。除此之外,我们还使用compose navigation component移动了导航。

碎片组成

布局

我们在每个片段中都为每个片段创建了新的布局文件。

<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container_view_events"
    android:name="com.example.fragment.analytics.AnalyticsEventsFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</androidx.fragment.app.FragmentContainerView>

合成

我们编写了与AndroidViewBinding组合的通用FragmentHolder。它创建了Android布局资源。我们上面创建的布局文件将生成他们的Binding类,我们可以在AndroidViewBinding中膨胀和传递为BindingFactory

@Composable
fun <T : ViewBinding> FragmentHolderScreen(
    topBarTitle: String,
    androidViewBindingFactory: (inflater: LayoutInflater, parent: ViewGroup, attachToParent: Boolean) -> T,
    onBackPress: () -> Unit = {},
    androidViewBindingUpdate: T.() -> Unit = {},
) {
    Scaffold(
        topBar = {
            TopBar(title = topBarTitle, onBackPress = onBackPress)
        },
        content = { paddingValues ->
            AndroidViewBinding(
                factory = androidViewBindingFactory,
                modifier = Modifier.padding(paddingValues),
                update = androidViewBindingUpdate,
            )
        },
    )
}

导航

创建组合后,我们用Screen枚举定义了导航组件。

具有上述布局绑定和FragmentHolderScreenAnalyticsEventsFragment,最小化的Scaffold合奏看起来像这样,

Scaffold(
    content = { contentPadding ->
        NavHost(
            navController = navController,
            startDestination = Screen.Settings.route,
            Modifier.padding(contentPadding),
        ) {
            composable(Screen.Events.route) {
                FragmentHolderScreen(
                    topBarTitle = getString(R.string.toolbar_title_events),
                    androidViewBindingFactory = ComposeFragmentEventsBinding::inflate,
                    androidViewBindingUpdate = {
                        with(fragmentContainerViewEvents.getFragment<AnalyticsEventsFragment>()) {
                            // Reference of AnalyticsEventsFragment is available here
                        }
                    },
                    onBackPress = {
                        onBackPress(navController)
                    },
                )
            }
        }
    },
)

内/孩子碎片

我们内部的一些片段有导航,用户将进入儿童片段。在进行基于作曲的导航时,我们添加了这些孩子碎片作为Screen/route枚举的一部分。然后,我们在base片段类中设置了一个lambda函数(val navigateTo: (Screen) -> Unit),以处理单击操作以移至子片段。

共享流程

示例应用程序使用SharedPreferences,我们没有时间转到DataStore之类的东西。将一个屏幕移至Compose之后,它仍然效果很好。我们只是确保在主要活动的onCreate中定义SharedPreferences的引用,然后将参考转移到可合曲。由于我们没有触摸现有的片段,因此他们使用的SharedPreferences已经定义。

UI测试

我们在测试SDK的示例应用程序中进行了广泛的UI测试。将示例应用程序的主屏幕移至Compose之后,我们打破了所有测试的入口点。

幸运的是,组成UI测试和浓缩咖啡测试彼此效果很好。您可以在单行测试中编写撰写测试,该测试是基于撰写的屏幕,第二行可以是观看视图层的意式浓缩板测试步骤。

我们围绕更新单元测试而面临的最大问题是两个系统之间的延迟。单击基于撰写的屏幕上的按钮后,该应用将转到SDK(基于视图的UI)。许多测试失败了,因为测试执行时,该视图将在屏幕上不可用。在尝试了几件事之后,除了在我们处理基于撰写的屏幕上单击按钮之前和之后添加Thread.sleep()之外,没有什么好工作了。延迟可能给了浓缩咖啡足够的时间找到正确的基于视图的屏幕。

结论

总的来说,我们对整个实验的进行方式感到满意。我们学到了一些有关撰写视图Interop的信息,并有机会通过此博客文章分享我们的发现。


感谢您的阅读!如果您有疑问,请在评论中告诉我。另外,您可以在Twitter,LinkedInKotlin Slack@shaktiman_droid与我联系。而且,如果您发现所有这些有趣的事