滚动视图中的异常情况

5

在我的安卓应用中,我遇到了一个IllegalStateException。但是我无法再次重现这个异常。以下是堆栈跟踪信息

Non-fatal Exception: java.lang.IllegalStateException: ScrollView can host only one direct child
       at android.widget.ScrollView.addView(ScrollView.java:397)
       at android.support.design.widget.BaseTransientBottomBar.showView(BaseTransientBottomBar.java:436)
       at android.support.design.widget.BaseTransientBottomBar$1.handleMessage(BaseTransientBottomBar.java:178)
       at android.os.Handler.dispatchMessage(Handler.java:98)
       at android.os.Looper.loop(Looper.java:146)
       at android.app.ActivityThread.main(ActivityThread.java:5679)
       at java.lang.reflect.Method.invokeNative(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:515)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
       at dalvik.system.NativeStart.main(NativeStart.java)  

有人能帮我吗?


3
看起来你正在显示一个带有目标ViewSnackbar,但这个View位于某个层次结构中,该层次结构没有CoordinatorLayoutandroid.R.id.content容器,但它确实有一个作为回退的ScrollView,因为ScrollView是一个FrameLayout。你在你的应用程序中使用了Snackbar吗?如果是的话,在哪里使用了? - Mike M.
1
是的,看起来有可能。如果你能缩小到那个问题,你可以提交一个错误报告。或者使用其他东西。 - Mike M.
1
仅限于操作系统版本低于Lollipop的设备出现问题。 - vm345
3
是的,我之所以说它看起来像是一个可能的原因,是因为它有两个内部“Snackbar”辅助类的不同实现;一个是针对Android 5.0以下版本的,另一个是针对更新版本的。我建议您在Android 5.0以下的版本上测试您的应用程序,如果能够复现此问题,请提供最小设置并提交错误报告。 - Mike M.
2
我有一些空闲时间,所以我在一个我可以使用的KitKat设备上对那个库进行了一些测试。我尝试了我能想到的每种方式,但我无法重现你遇到的问题。事实上,我唯一能够让“Snackbar”像那样失败的方法是在一个带有“ScrollView”的“PopupWindow”中显示它作为内容。我能想到的每种其他配置都会在层次结构中进一步添加另一个合格的“FrameLayout”。即使该库是问题的一部分,我也必须说这与你的确切设置有关。如果您能够重现它,请尽可能添加详细信息。 - Mike M.
显示剩余13条评论
7个回答

2

我仔细研究了这个问题,逻辑上发现它与在片段或活动中显示Snackbar有关,在停止(onStop())和销毁(onDestroy())生命周期回调阶段分别作为全局对象在另一个类中被引用时,需要注意失效问题:

https://stackoverflow.com/a/52019719/787399


1

滚动视图只能有一个直接子元素

示例: 这是有效的-->

ScrollView
    LinearLayout
        Other Views
        ....
        ....
    LinearLayout
ScrollView

这不是-->

ScrollView
    LinearLayout
        Other Views
        ....
        ....
    LinearLayout
    LinearLayout
        Other Views
        ....
        ....
    LinearLayout

ScrollView

1
在ScrollView中,你需要托管一个子项(例如LinearLayout),该子项将托管来自滚动视图的所有UI元素。例如,你不能直接将两个TextView添加到ScrollView中,你需要有一个东西来容纳这些UI元素。

1
在ScrollView中,您只能有一个View(我是指TextView、Button等,但ViewGroup也是View的子类),或ViewGroup。因此,如果您有多个View,请将它们放入适当的ViewGroup中,它就可以正常工作了。

1
我遇到了同样的问题,并且已经使用以下步骤重现。
步骤1:使用ScrollView作为Fragment或Activity布局的父控件。
步骤2:在onPause()、onStop()、onDestroy()中显示Snackbar,如下所示。
@Override
    public void onPause() {
        super.onPause();
        Snackbar.make(button, "onPause", Snackbar.LENGTH_LONG).show();
    }

    @Override
    public void onStop() {
        super.onPause();
        Snackbar.make(button, "onStop", Snackbar.LENGTH_LONG).show();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        Snackbar.make(button, "onDestroy", Snackbar.LENGTH_LONG).show();
    }

现在运行一个应用程序并在logcat中检查。当您单击“后退”按钮时,您将获得与问题中提到的相同错误。
解决方案:
创建一个通用的Snackbar,如下所示。
@Override
        public void onPause() {
            super.onPause();
            showSnackbar("onPause");
        }

        @Override
        public void onStop() {
            super.onPause();
            showSnackbar("onStop");
        }

        @Override
        public void onDestroy() {
            super.onDestroy();
            showSnackbar("onDestroy");
        }

    private void showSnackbar(String message) {
            if (isValidContext(getActivity())) {
                Snackbar.make(btnConsume, message, Snackbar.LENGTH_LONG).show();
            } 
        }

    public static boolean isValidContext(final Context context) {

            if (context == null) {
                return false;
            }
            if (context instanceof Activity) {
                final Activity activity = (Activity) context;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                    return !activity.isDestroyed() && !activity.isFinishing();
                } else {
                    return !activity.isFinishing();
                }
            }
            return true;

        }

0

ScrollView不接受多个子元素,只能在ScrollView内使用一个布局,如LinearLayout、RelativeLayout、FrameLayout或ConstraintLayout(根据您的需求),然后添加所有子元素。

请参考以下内容

 <?xml version="1.0" encoding="utf-8"?>
    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

          //Add your Views here
        </android.support.constraint.ConstraintLayout>
    </ScrollView>

0
滚动视图只允许直接有一个子元素,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">
     <ScrollView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
       <!--Here scroll view allow only one direct child-->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
           <!--Here your other xml code-->
        </LinearLayout>
    </ScrollView>
 </LinearLayout>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接