TypedArray.getText() 在 android.R.attr.text returns 空
TypedArray.getText() on android.R.attr.text returns null
我正在尝试实现一个使用 StaticLayout 的自定义文本视图。为了获得视图的 'android:text' 属性,我在初始化字段中这样实现:
@SupressLint("ResourceType")
class ExampleTextView(context: Context, attrs: AttributeSet?, defStyleAttr: Int): View(...) {
private var mText: String
init {
val styledAttributes = context.obtainStyledAttributes(attrs, intArrayOf(
...
android.R.attr.text,
...
))
mText = styledAttributes.getText(1)
...
styledAttributes.recycle()
}
...
}
然后在布局中xml:
<com.example.package.ExampleTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is an example text" />
我 显然 在自定义文本视图中设置了 'android:text'。但是当我尝试从 TypedArray 获取属性时,它 return 为空。 styledAttributes.getString(1)
的另一次尝试也使 return 为空。
堆栈跟踪:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.package, PID: 19154
android.view.InflateException: Binary XML file line #10: Binary XML file line #10: Error inflating class com.example.package.ExampleTextView
Caused by: android.view.InflateException: Binary XML file line #10: Error inflating class com.example.package.ExampleTextView
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:647)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:790)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at com.example.package.adapter.elementsAdapter.onCreateViewHolder(PatchNoteElementsAdapter.kt:54)
at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7078)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6235)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404)
at android.view.View.layout(View.java:20691)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at com.google.android.material.appbar.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:148)
at com.google.android.material.appbar.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:43)
at com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1996)
at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:918)
at android.view.View.layout(View.java:20691)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20691)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at android.view.View.layout(View.java:20691)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20691)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at android.view.View.layout(View.java:20691)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
E/AndroidRuntime: at com.android.internal.policy.DecorView.onLayout(DecorView.java:765)
at android.view.View.layout(View.java:20691)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2806)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2333)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1473)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7215)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1004)
at android.view.Choreographer.doCallbacks(Choreographer.java:816)
at android.view.Choreographer.doFrame(Choreographer.java:751)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:990)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:280)
at android.app.ActivityThread.main(ActivityThread.java:6706)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: kotlin.KotlinNullPointerException
at com.example.package.ExampleTextView.<init>(ExampleTextView.kt:66)
at com.example.package.ExampleTextView.<init>(ExampleTextView.kt:22)
... 67 more
有什么我遗漏的吗?
我导入了您的 TextView 并发现了与内部异常相同的异常
java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet]
我怀疑这与 attrs
的设置方式有关
通常当我扩展一个通用视图时,我会公开所有可用的构造函数,试一试。
class ExampleTextView: View {
constructor(context: Context): super(context)
constructor(context: Context, attrs: AttributeSet?): super(context, attrs) {
this.attrs = attrs
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int): super(context, attrs, defStyleAttr) {
this.attrs = attrs
}
private var mText: String
private var attrs: AttributeSet? = null
init {
val styledAttributes = context.obtainStyledAttributes(attrs, intArrayOf(android.R.attr.text))
mText = styledAttributes.getText(1).toString()
styledAttributes.recycle()
}
}
简短回答:按升序对属性 ID 进行排序。
我找到了答案。这是因为在 context.obtainStyledAttributes().
上作为参数传递的 IntArray 的顺序
我在定义styledAttributes的时候是这样写的:
val styledAttributes = context.obtainStyledAttributes(attrs, intArrayOf(
android.R.attr.fontFamily,
android.R.attr.text,
android.R.attr.textSize,
android.R.attr.textColor,
android.R.attr.textAlignment,
android.R.attr.lineSpacingExtra
))
根据上文,styledAttributes 未排序。我们通过 android studio 文档 (Ctrl+Q) 查看常量值时就可以知道。等于:
val styledAttributes = context.obtainStyledAttributes(attrs, intArrayOf(
16843692,
16843087,
16842901,
16842904,
16843697,
16843287
))
虽然我没有在问题中提到,但当我尝试获取 textSize 和 lineSpacingExtra 的值时,我也得到了 null。
为什么?因为用无序列表调用 obtainStyledAttributes 时,无论你做什么,属性值都将为 null; getText(), getString(), getDimension(), getFont(), getResourceId(), 等等...如果属性常量的下一个值小于前一个。
这就是我尝试获取比以前小的属性常量16843087、16842901、16843287的值时得到空值的原因; 16843692, 16843087, 16843697.
此外,根据 Android 开发者参考,他们显然是说属性常量数组必须按升序排序。 https://developer.android.com/reference/android/content/res/Resources.Theme#obtainStyledAttributes(android.util.AttributeSet,%20int[],%20int,%20int)
attrs | int: The desired attributes in the style. These attribute IDs must be sorted in ascending order. This value cannot be null.
所以,为了正确获取属性值,我应该这样做:
val styledAttributes = context.obtainStyledAttributes(attrs, intArrayOf(
android.R.attr.textSize,
android.R.attr.textColor,
android.R.attr.text,
android.R.attr.lineSpacingExtra,
android.R.attr.fontFamily,
android.R.attr.textAlignment
))
升序排列的很好。希望这对未来的读者有所帮助。
我正在尝试实现一个使用 StaticLayout 的自定义文本视图。为了获得视图的 'android:text' 属性,我在初始化字段中这样实现:
@SupressLint("ResourceType")
class ExampleTextView(context: Context, attrs: AttributeSet?, defStyleAttr: Int): View(...) {
private var mText: String
init {
val styledAttributes = context.obtainStyledAttributes(attrs, intArrayOf(
...
android.R.attr.text,
...
))
mText = styledAttributes.getText(1)
...
styledAttributes.recycle()
}
...
}
然后在布局中xml:
<com.example.package.ExampleTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is an example text" />
我 显然 在自定义文本视图中设置了 'android:text'。但是当我尝试从 TypedArray 获取属性时,它 return 为空。 styledAttributes.getString(1)
的另一次尝试也使 return 为空。
堆栈跟踪:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.package, PID: 19154
android.view.InflateException: Binary XML file line #10: Binary XML file line #10: Error inflating class com.example.package.ExampleTextView
Caused by: android.view.InflateException: Binary XML file line #10: Error inflating class com.example.package.ExampleTextView
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:647)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:790)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at com.example.package.adapter.elementsAdapter.onCreateViewHolder(PatchNoteElementsAdapter.kt:54)
at androidx.recyclerview.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:7078)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6235)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6118)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6114)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2303)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1627)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1587)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:665)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4134)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3851)
at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4404)
at android.view.View.layout(View.java:20691)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at com.google.android.material.appbar.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:148)
at com.google.android.material.appbar.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:43)
at com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1996)
at androidx.coordinatorlayout.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:918)
at android.view.View.layout(View.java:20691)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20691)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at android.view.View.layout(View.java:20691)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:20691)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)
at android.view.View.layout(View.java:20691)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
E/AndroidRuntime: at com.android.internal.policy.DecorView.onLayout(DecorView.java:765)
at android.view.View.layout(View.java:20691)
at android.view.ViewGroup.layout(ViewGroup.java:6194)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2806)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2333)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1473)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7215)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1004)
at android.view.Choreographer.doCallbacks(Choreographer.java:816)
at android.view.Choreographer.doFrame(Choreographer.java:751)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:990)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:280)
at android.app.ActivityThread.main(ActivityThread.java:6706)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: kotlin.KotlinNullPointerException
at com.example.package.ExampleTextView.<init>(ExampleTextView.kt:66)
at com.example.package.ExampleTextView.<init>(ExampleTextView.kt:22)
... 67 more
有什么我遗漏的吗?
我导入了您的 TextView 并发现了与内部异常相同的异常
java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet]
我怀疑这与 attrs
的设置方式有关
通常当我扩展一个通用视图时,我会公开所有可用的构造函数,试一试。
class ExampleTextView: View {
constructor(context: Context): super(context)
constructor(context: Context, attrs: AttributeSet?): super(context, attrs) {
this.attrs = attrs
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int): super(context, attrs, defStyleAttr) {
this.attrs = attrs
}
private var mText: String
private var attrs: AttributeSet? = null
init {
val styledAttributes = context.obtainStyledAttributes(attrs, intArrayOf(android.R.attr.text))
mText = styledAttributes.getText(1).toString()
styledAttributes.recycle()
}
}
简短回答:按升序对属性 ID 进行排序。
我找到了答案。这是因为在 context.obtainStyledAttributes().
上作为参数传递的 IntArray 的顺序我在定义styledAttributes的时候是这样写的:
val styledAttributes = context.obtainStyledAttributes(attrs, intArrayOf(
android.R.attr.fontFamily,
android.R.attr.text,
android.R.attr.textSize,
android.R.attr.textColor,
android.R.attr.textAlignment,
android.R.attr.lineSpacingExtra
))
根据上文,styledAttributes 未排序。我们通过 android studio 文档 (Ctrl+Q) 查看常量值时就可以知道。等于:
val styledAttributes = context.obtainStyledAttributes(attrs, intArrayOf(
16843692,
16843087,
16842901,
16842904,
16843697,
16843287
))
虽然我没有在问题中提到,但当我尝试获取 textSize 和 lineSpacingExtra 的值时,我也得到了 null。
为什么?因为用无序列表调用 obtainStyledAttributes 时,无论你做什么,属性值都将为 null; getText(), getString(), getDimension(), getFont(), getResourceId(), 等等...如果属性常量的下一个值小于前一个。
这就是我尝试获取比以前小的属性常量16843087、16842901、16843287的值时得到空值的原因; 16843692, 16843087, 16843697.
此外,根据 Android 开发者参考,他们显然是说属性常量数组必须按升序排序。 https://developer.android.com/reference/android/content/res/Resources.Theme#obtainStyledAttributes(android.util.AttributeSet,%20int[],%20int,%20int)
attrs | int: The desired attributes in the style. These attribute IDs must be sorted in ascending order. This value cannot be null.
所以,为了正确获取属性值,我应该这样做:
val styledAttributes = context.obtainStyledAttributes(attrs, intArrayOf(
android.R.attr.textSize,
android.R.attr.textColor,
android.R.attr.text,
android.R.attr.lineSpacingExtra,
android.R.attr.fontFamily,
android.R.attr.textAlignment
))
升序排列的很好。希望这对未来的读者有所帮助。