CustomView 无法实例化(编辑器预览错误,编译后没有显示)
Posted
技术标签:
【中文标题】CustomView 无法实例化(编辑器预览错误,编译后没有显示)【英文标题】:CustomView couldn't be instantiated (error in editor preview and nothing shown after compile) 【发布时间】:2017-09-24 05:35:35 【问题描述】:所以,我创建了一个名为ButtonWithCaption.xml
的CustomView
,
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:layout_weight="1"
android:background="?attr/selectableItemBackground"
android:paddingBottom="@dimen/spacing_normal"
android:paddingLeft="@dimen/spacing_small"
android:paddingRight="@dimen/spacing_small"
android:paddingTop="@dimen/spacing_normal">
<ImageView
android:id="@+id/bwc_icon"
android:layout_
android:layout_
android:layout_centerHorizontal="true"
android:layout_marginBottom="2dp"
android:scaleType="centerCrop" />
<TextView
android:id="@+id/bwc_caption"
android:layout_
android:layout_
android:layout_below="@id/bwc_icon"
android:textAlignment="center" />
连同它的控制器ButtonWithCaption.java
public class ButtonWithCaption extends RelativeLayout
private ImageView mImageView;
private TextView mTextView;
private int mIconSrc;
private String mCaptionText;
private boolean mShowIcon;
private boolean mShowText;
public ButtonWithCaption(Context context)
super(context);
init(context, null, 0);
public ButtonWithCaption(Context context, AttributeSet attrs)
super(context, attrs);
init(context, attrs, 0);
public ButtonWithCaption(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
private void init(Context context, AttributeSet attrs, int defStyleAttr)
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ButtonWithCaption, 0, 0);
try
mIconSrc = a.getResourceId(R.styleable.ButtonWithCaption_iconSrc, 0);
mCaptionText = a.getString(R.styleable.ButtonWithCaption_captionText);
mShowIcon = a.getBoolean(R.styleable.ButtonWithCaption_showIcon, mIconSrc != 0);
mShowText = a.getBoolean(R.styleable.ButtonWithCaption_showText, !mCaptionText.isEmpty());
mImageView = (ImageView) findViewById(R.id.bwc_icon);
mTextView = (TextView) findViewById(R.id.bwc_caption);
mImageView.setImageResource(mIconSrc);
mTextView.setText(mCaptionText);
finally
a.recycle();
没什么特别的。
然后,我在attrs.xml
中声明自定义属性
<resources>
<declare-styleable name="ButtonWithCaption">
<attr name="iconSrc" format="reference" />
<attr name="captionText" format="string" />
<attr name="showIcon" format="boolean" />
<attr name="showText" format="boolean" />
</declare-styleable>
</resources>
这是我的activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
tools:context="id.foodmap.foodmapcustomviews.MainActivity">
<id.foodmap.foodmapcustomviews.ButtonWithCaption
android:id="@+id/button_with_caption"
android:layout_
android:layout_
app:captionText="Test"
app:iconSrc="@drawable/ic_email_gray_24dp" />
</RelativeLayout>
...但奇怪的是,Android Studio 的预览给了我渲染错误:
无法实例化一个或多个类
使用堆栈跟踪:
java.lang.NullPointerException 在 id.foodmap.foodmapcustomviews.ButtonWithCaption.init(ButtonWithCaption.java:54) 在 id.foodmap.foodmapcustomviews.ButtonWithCaption.(ButtonWithCaption.java:29) 在 sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 在 sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) 在 sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 在 java.lang.reflect.Constructor.newInstance(Constructor.java:423) 在 org.jetbrains.android.uipreview.ViewLoader.createNewInstance(ViewLoader.java:475) 在 org.jetbrains.android.uipreview.ViewLoader.loadClass(ViewLoader.java:262) 在 org.jetbrains.android.uipreview.ViewLoader.loadView(ViewLoader.java:220) 在 com.android.tools.idea.rendering.LayoutlibCallbackImpl.loadView(LayoutlibCallbackImpl.java:186) 在 android.view.BridgeInflater.loadCustomView(BridgeInflater.java:334) 在 android.view.BridgeInflater.loadCustomView(BridgeInflater.java:345) 在 android.view.BridgeInflater.createViewFromTag(BridgeInflater.java:245) 在 android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:727) 在 android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:858) 在 android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:70) 在 android.view.LayoutInflater.rInflate(LayoutInflater.java:834) 在 android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:821) 在 android.view.LayoutInflater.inflate(LayoutInflater.java:518) 在 android.view.LayoutInflater.inflate(LayoutInflater.java:397) 在 com.android.layoutlib.bridge.impl.RenderSessionImpl.inflate(RenderSessionImpl.java:324) 在 com.android.layoutlib.bridge.Bridge.createSession(Bridge.java:429) 在 com.android.ide.common.rendering.LayoutLibrary.createSession(LayoutLibrary.java:368) 在 com.android.tools.idea.rendering.RenderTask$2.compute(RenderTask.java:567) 在 com.android.tools.idea.rendering.RenderTask$2.compute(RenderTask.java:549) 在 com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:863) 在 com.android.tools.idea.rendering.RenderTask.createRenderSession(RenderTask.java:549) 在 com.android.tools.idea.rendering.RenderTask.lambda$inflate$1(RenderTask.java:680) 在 java.util.concurrent.FutureTask.run(FutureTask.java:266) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 在 java.lang.Thread.run(Thread.java:745)
我的findViewById()
从ButtonWithCaption.java
找到TextView
和ImageView
也返回null。
有人知道是什么原因造成的吗?因为它甚至没有出现在编辑器预览窗口中。
附:如果我使用 ,预览会正确显示元素。
P.S.S.它编译到我的手机没有错误,但没有显示ButtonWithCaption
。
提前致谢
【问题讨论】:
你在声明的 xml 中的自定义视图在哪里? ButtonWithCaption.java 的第 54 行是什么? 另外,显示使用 ButtonWithCaption 的代码?您是在activity_main.xml
或其他布局文件中使用它吗?或者您是否尝试从 Java 代码动态创建 ButtonWithCaption?
@Code-Apprentice 第 54 行:mImageView.setImageResource(mIconSrc);
是的。我忘了粘贴activity_main.xml
文件。刚刚添加。
【参考方案1】:
您获得了NullPointerException
,因为您没有夸大来自ButtonWithCaption.xml
的视图。解决此问题的一种方法是使用静态 View.inflate()
方法:
private void init(Context context, AttributeSet attrs, int defStyleAttr)
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ButtonWithCaption, 0, 0);
try
mIconSrc = a.getResourceId(R.styleable.ButtonWithCaption_iconSrc, 0);
mCaptionText = a.getString(R.styleable.ButtonWithCaption_captionText);
mShowIcon = a.getBoolean(R.styleable.ButtonWithCaption_showIcon, mIconSrc != 0);
mShowText = a.getBoolean(R.styleable.ButtonWithCaption_showText, !mCaptionText.isEmpty());
View v = View.inflate(context, R.layout.ButtonWithCaption, this); // add this line
mImageView = (ImageView) findViewById(R.id.bwc_icon);
mTextView = (TextView) findViewById(R.id.bwc_caption);
mImageView.setImageResource(mIconSrc);
mTextView.setText(mCaptionText);
finally
a.recycle();
【讨论】:
好的,漂亮。我以为我以前试过? Idk,但这有点奇怪,我想,如果这个类已经被调用,那是不是意味着我已经在 xml 中声明了它?为什么我们需要再次充气呢?虽然没有意义。 (我认为,通货膨胀应该自动发生,因为我已经在 xml 中声明了它吗?) @MosesAprico 不,XML 布局永远不会自动膨胀。甚至活动的布局也必须通过调用setContentView()
来扩展。
好吧,你知道这种行为背后的原因吗?因为我觉得这很奇怪。因为,为什么我什至在我的 XML 上放了一些我不想被夸大的东西?顺便说一句,我是一名 C# 和 XAML 程序员,我放入 XAML(C# 的 Android 布局 XML 版本)中的元素会在我的代码隐藏中自动初始化。
@MosesAprico 当您调用 View.inflate() 时,XML 会膨胀。另一种方法是直接在 Java 中创建所有视图,这将需要大量代码。就个人而言,我认为使用 XML 更简单、更干净。
我的意思是,当有人在 XML 中声明一个视图时,是否意味着“某人”希望它被夸大?我的意思是,为什么谷歌将其设计为不自动充气?有没有其他人想要的情况?【参考方案2】:
您必须将标签 <RelativeLayout>
替换为您的班级,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<com.yourpackage.app.ButtonWithCaption xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
...
>
...
</com.yourpackage.app.ButtonWithCaption>
com.yourpackage.app 应该是 ButtonWithCaptionclass 所在的路径。
编辑:
A您发布的布局应该是您的活动布局,ButtonWithCaptionclass 应该是您的 xml 元素,而不是您的 xml 名称,因此请更改名称,将 RelativeLayout
替换为您的自定义类并尝试一下。
【讨论】:
我假设您指的是 ButtonWithCaption.xml 文件中的 RelativeLayout。这个建议是不正确的。<id.foodmap.foodmapcustomviews.ButtonWithCaption>
,例如activity_main.xml
或2. 在Java 代码中以编程方式创建ButtonWithCaption
实例。在这两种情况下,您都应该在ButtonWithCaption.xml
中使用<id.foodmap.foodmapcustomviews.ButtonWithCaption>
。当ButtionWithCaption
类尝试膨胀布局时,这将导致无限递归。
"正如 Code-Apprentice 所说,您发布的布局应该是您的活动布局" 这不是我说的。发布的布局与ButtonWithCaption.xml
一样好。我已经发布了一个答案,解释了真正的问题是什么以及如何解决它。
现在我明白了。但是,现在我问是因为我只想知道,您在 RelativeLayout 中有一个 RelativeLayout,这需要吗?我的意思是,您的自定义布局扩展了RelativeLayout,并在您的xml 中声明了另一个Relative。以上是关于CustomView 无法实例化(编辑器预览错误,编译后没有显示)的主要内容,如果未能解决你的问题,请参考以下文章
Unity 自定义编辑器 Raycast 在实例化对象后无法正常工作