通过Android 源码分析ScrollView ‘ScrollView can host only one direct child’错误问题。
我们在初次使用SrollView的时候,可能会遇到 ScrollView can host only one direct child 的错误。
02-14 15:41:02.310 6111-6111/wjc.random.patternlock.demo E/AndroidRuntime: FATAL EXCEPTION: main
Process: wjc.random.patternlock.demo, PID: 6111
java.lang.RuntimeException: Unable to start activity ComponentInfo{wjc.random.patternlock.demo/wjc.random.patternlock.demo.PhotoActivity}: android.view.InflateException: Binary XML file line #30: ScrollView can host only one direct child
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2576)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2658)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1492)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5737)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
Caused by: android.view.InflateException: Binary XML file line #30: ScrollView can host only one direct child
at android.view.LayoutInflater.inflate(LayoutInflater.java:539)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:413)
at android.app.Activity.setContentView(Activity.java:2191)
at wjc.random.patternlock.demo.PhotoActivity.onCreate(PhotoActivity.java:22)
at android.app.Activity.performCreate(Activity.java:6309)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1113)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2523)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2658)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1492)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5737)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
现在为通过来看看报错地源码:ScrollView.java
@Override
public void addView(View child) {
if (getChildCount() > 0) {
throw new IllegalStateException("ScrollView can host only one direct child");
}
super.addView(child);
}
@Override
public void addView(View child, int index) {
if (getChildCount() > 0) {
throw new IllegalStateException("ScrollView can host only one direct child");
}
super.addView(child, index);
}
@Override
public void addView(View child, ViewGroup.LayoutParams params) {
if (getChildCount() > 0) {
throw new IllegalStateException("ScrollView can host only one direct child");
}
super.addView(child, params);
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if (getChildCount() > 0) {
throw new IllegalStateException("ScrollView can host only one direct child");
}
在addview的时候,ScrollView会判断childcount,等已经存在一个childcount时,在addview就会报错。
同样在onMeasure 中也要求一个childcount: final View child = getChildAt(0);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (!mFillViewport) {
return;
}
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode == MeasureSpec.UNSPECIFIED) {
return;
}
if (getChildCount() > 0) {
final View child = getChildAt(0);
final int height = getMeasuredHeight();
if (child.getMeasuredHeight() < height) {
final int widthPadding;
final int heightPadding;
final FrameLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
if (targetSdkVersion >= VERSION_CODES.M) {
widthPadding = mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin;
heightPadding = mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin;
} else {
widthPadding = mPaddingLeft + mPaddingRight;
heightPadding = mPaddingTop + mPaddingBottom;
}
final int childWidthMeasureSpec = getChildMeasureSpec(
widthMeasureSpec, widthPadding, lp.width);
final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
height - heightPadding, MeasureSpec.EXACTLY);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}
}
通过上面的源码,我们就知道报错的原因了,addview>1了。
造成以上原因的实例:
1。layout布局中静态加载错误:
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/scroll"
android:layout_gravity="center_horizontal" >
<LinearLayout
android:id="@+id/content"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"></LinearLayout>
//多加了下面的LinearLayout,应去掉
<LinearLayout
android:id="@+id/content1"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"></LinearLayout>
</ScrollView>
2.动态加载过程的错误:
mScroll = (ScrollView)findViewById(R.id.scroll);
// mScroll 只能一次addview
for (int i=0;i<100;i++){
TextView textView = new TextView(this);
textView.setText("cntent "+i);
mScroll.addView(textView);
}