android - 使用 Material Design 主题进行 fragment 隔离测试

标签 android android-fragments material-design android-testing

我有一个单一 Activity 的设置,mutli 功能模块,看起来像这样:

/app - 包含样式资源的主模块,继承了 Material Design 的样式资源和 Activity /menu - 只有 fragment 和 View 模型的模块功能 /其他模块...

我试图在我的 Android 测试中单独运行我的 fragment ,这导致了一个错误,即 Material 组件(在本例中为 CardView)必须将 Material Theme 作为其样式。这确实有道理,但我试过了。

现在我得到这个错误

android.view.InflateException: Binary XML file line #21 in com.nikolam.menu.test:layout/menu_item: Binary XML file line #21 in com.nikolam.menu.test:layout/menu_item: Error inflating class com.google.android.material.card.MaterialCardView
Caused by: android.view.InflateException: Binary XML file line #21 in com.nikolam.menu.test:layout/menu_item: Error inflating class com.google.android.material.card.MaterialCardView
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
at android.view.LayoutInflater.createView(LayoutInflater.java:854)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1006)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:961)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1123)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
at android.view.LayoutInflater.inflate(LayoutInflater.java:682)
at android.view.LayoutInflater.inflate(LayoutInflater.java:534)
at com.nikolam.menu.ui.menu.adapter.MenuAdapter.onCreateViewHolder(MenuAdapter.kt:27)
at com.nikolam.menu.ui.menu.adapter.MenuAdapter.onCreateViewHolder(MenuAdapter.kt:16)
at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7266)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6397)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6281)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6277)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2330)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1631)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1591)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:668)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4277)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3980)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4546)
at android.view.View.layout(View.java:21912)
at android.view.ViewGroup.layout(ViewGroup.java:6260)
at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1915)
at android.view.View.layout(View.java:21912)
at android.view.ViewGroup.layout(ViewGroup.java:6260)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at android.view.View.layout(View.java:21912)
at android.view.ViewGroup.layout(ViewGroup.java:6260)
at com.android.internal.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:509)
at android.view.View.layout(View.java:21912)
at android.view.ViewGroup.layout(ViewGroup.java:6260)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:779)
at android.view.View.layout(View.java:21912)
at android.view.ViewGroup.layout(ViewGroup.java:6260)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:3080)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2590)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1721)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7598)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:966)
at android.view.Choreographer.doCallbacks(Choreographer.java:790)
at android.view.Choreographer.doFrame(Choreographer.java:725)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:951)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.IllegalArgumentException: The style on this component requires your app theme to be Theme.MaterialComponents (or a descendant).
at com.google.android.material.internal.ThemeEnforcement.checkTheme(ThemeEnforcement.java:240)
at com.google.android.material.internal.ThemeEnforcement.checkMaterialTheme(ThemeEnforcement.java:215)
at com.google.android.material.internal.ThemeEnforcement.checkCompatibleTheme(ThemeEnforcement.java:143)
at com.google.android.material.internal.ThemeEnforcement.obtainStyledAttributes(ThemeEnforcement.java:78)
at com.google.android.material.card.MaterialCardView.<init>(MaterialCardView.java:128)
at com.google.android.material.card.MaterialCardView.<init>(MaterialCardView.java:118)

这是不言自明的,但这是布局的问题,它需要继承 Material 设计风格。它是做什么的。这只是在隔离环境(测试)中运行它时的问题,否则它可以正常工作。我猜容器中的 Fragment 没有引用样式,但我随后将其添加到 CardView 本身,这让我更加困惑。

@Before
    fun setUp() {
        launchFragmentInContainer<MenuFragment>()
    }
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.google.android.material.card.MaterialCardView
            style="@style/Theme.MaterialComponents.DayNight"
            android:id="@+id/materialCardView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.5"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/name_textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{item.name}"
            android:textSize="30dp"
            app:layout_constraintHorizontal_bias="0.212"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/options_recycle_view"
            adapter="@{adapter}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/name_textView"
            app:layout_constraintTop_toTopOf="@+id/materialCardView" />


    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

list 中引用了应用主题。并且整个应用的样式只存在于app模块中,Menu模块没有自己的style.xml文件。该应用程序包含项目的唯一 Activity 。我试图找到其他人有同样的问题,但没有运气。

最佳答案

FragmentScenario API 允许您为 fragment 容器明确设置所需的主题。

styles.xml 中将应用程序主题定义为 AppTheme 并具有 parent=Theme.MaterialComponents 属性,一个可能的 MenuFragment 启动调用如下:

FragmentScenario.launchInContainer(MenuFragment.class, null, R.style.AppTheme, null);

请参阅 FragmentScenario 文档,了解对超出此答案范围的其余参数的解释。

关于android - 使用 Material Design 主题进行 fragment 隔离测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63541027/

相关文章:

java - 如何在 Java 中设置 GET 请求中的参数

android - 由于意外的 uninstall.exe 文件,更新到 Android Studio 0.8.16 失败

android - 每次拉动时拉动刷新错误都会继续添加

javascript - React - 如何手动触发子组件的鼠标输入

android - AsyncTask - 如何在使用已更新的值之前等待 onPostExecute() 完成

android - DialogFragment 在方向更改时被解雇

java - 尝试调用虚方法

android - ImageButton 的 Material Design 指南是什么?

android - 状态栏颜色不会随着相对布局作为根元素而改变

javascript - Jingle 和 webRTC 之间的互操作性