findViewByID返回null

时间:2010-07-16 12:02:35

标签: android android-view

首先:是的,我阅读了有关此主题的所有其他主题。而且不仅是来自这个网站的人......(你看,我有点沮丧)

他们中的大多数都提出了在XML文件中使用android:id而不仅仅是id的建议。我做到了。

我从其他人那里了解到,View.findViewById的工作方式与Activity.findViewById不同。我也处理了这个问题。

在我的location_layout.xml中,我使用:

<FrameLayout .... >
    <some.package.MyCustomView ... />

    <LinearLayout ... >
        <TextView ...
            android:id="@+id/txtLat" />
        ...
    </LinearLayout>
</FrameLayout>

在我的活动中,我做了:

...
setContentView( R.layout.location_layout );

并在我的自定义视图类中:

... 
TextView tv = (TextView) findViewById( R.id.txtLat );

返回null这样做,我的活动工作正常。所以可能是因为Activity.findViewByIdView.findViewById的差异。所以我在本地存储了传递给海关视图构造函数的上下文并尝试:

...
TextView tv = (TextView) ((Activity) context).findViewById( R.id.txtLat );

也返回null

然后,我更改了自定义视图以扩展ViewGroup而不是View并更改了location_layout.xml以让TextView成为我的自定义视图的直接子项,以便View.findViewById应该按照假设工作。惊喜:它没有解决任何问题。

那么我做错了什么?

我会感激任何评论。

29 个答案:

答案 0 :(得分:248)

  

返回null

可能是因为你太早说了。等到onFinishInflate()Here is a sample project演示了访问其内容的自定义View

答案 1 :(得分:138)

您可能在致电findViewById之前致电setContentView? 如果是这种情况,请尝试拨打findViewById AFTER 致电setContentView

答案 2 :(得分:95)

确保您的布局没有多个版本,以适应不同的屏幕密度。我在向现有布局添加新ID但忘记更新hdpi版本时遇到此问题。如果您忘记更新布局文件的所有版本,它将适用于某些屏幕密度,但不适用于其他版本。

答案 3 :(得分:15)

就我而言,我的项目中有2个活动,main.xmlmain2.xml。从一开始,main2就是main的副本,一切运作良好,直到我向TextView添加了新的main2,因此R.id.textview1可用于应用程序的其余部分。然后我尝试通过标准调用来获取它:

TextView tv = (TextView) findViewById( R.id.textview1 );

它始终为空。事实证明,在onCreate构造函数中,我实例化的不是main2,而是另一个。{1}}。我有:

setContentView(R.layout.main);

而不是

setContentView(R.layout.main2);

我到达这里后,在网站上注意到了这一点。

答案 4 :(得分:13)

如果在自定义视图中调用错误的超级构造函数,则FindViewById可以为null。 ID标记是attrs的一部分,因此如果忽略attrs,则删除ID。

这是错误的

public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context);
}

这是正确的

public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context,attrs);
}

答案 5 :(得分:13)

除了其他地方提到的经典原因外:

  • 确保您在setContentView()
  • 之前致电findViewById()
  • 确保您想要的id位于您setContentView()
  • 的视图或布局中
  • 确保id不会在不同的布局中意外重复

我在标准布局中找到了一个自定义视图,这违反了文档:

理论上,您可以创建自定义视图并将其添加到布局(see here)。但是,我发现在这种情况下,有时id属性适用于布局中除自定义视图之外的所有视图。我使用的解决方案是:

  1. 使用与您希望自定义视图相同的布局属性替换每个自定义视图FrameLayout。给它一个合适的id,比如frame_for_custom_view
  2. onCreate

    setContentView(R.layout.my_layout);
    FrameView fv = findViewById(R.id.frame_for_custom_layout);
    MyCustomView cv = new MyCustomView(context);
    fv.addView(cv);
    

    将自定义视图放在框架中。

答案 6 :(得分:8)

    @Override
protected void onStart() {
         // use findViewById() here instead of in onCreate()
    }

答案 7 :(得分:6)

使用ExpandableListView的人的答案,并根据它的标题运行这个问题。

我尝试在我的子视图和组视图中使用TextViews作为ExpandableListView实现的一部分时出现此错误。

您可以在getChildView()和getGroupView()方法的实现中使用以下内容。

        if (convertView == null) {
            LayoutInflater inflater =  (LayoutInflater) myContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.child_layout, null);
        }

我发现了here

答案 8 :(得分:5)

我对Android / Eclipse很陌生,错误地我将UI内容添加到activity_main.xml而不是fragment_main.xml。花了我几个小时来搞清楚......

答案 9 :(得分:4)

FWIW,我没有看到任何人以我想要的方式解决这个问题。在编译时没有抱怨,但我在运行时获得了一个空视图,并以正确的顺序调用事物。那是,     findViewById() 后的     的setContentView()。 问题是我的视图是在content_main.xml中定义的,但在我的activity_main.xml中,我缺少这一句话:

<include layout="@layout/content_main" />

当我将它添加到activity_main.xml时,不再有NullPointer。

答案 10 :(得分:3)

在我的特定情况下,我试图将一个页脚添加到ListView。 onCreate()中的以下调用返回null。

TextView footerView = (TextView) placesListView.findViewById(R.id.footer);

更改此项以扩充页脚视图而不是通过ID查找它解决了此问题。

View footerView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.footer_view, null, false);

答案 11 :(得分:3)

我的情况不像上面那样,没有解决方案有效。我认为我的观点对布局层次结构太深了。我将它向上移动了一级,它不再是空的。

答案 12 :(得分:2)

我有同样的问题。我使用的是第三方库,它允许您覆盖GridView的适配器并为每个GridView单元指定自己的布局。

我终于意识到发生了什么。 Eclipse仍然在GridView中为每个单元格使用库的布局xml文件,即使它没有给出任何指示。在我的自定义适配器中,它表明它正在使用我自己项目中的xml资源,即使在运行时,它也不是。

所以我所做的是确保我的自定义xml布局和ID与仍然位于库中的那些不同,清理项目然后它开始阅读我项目中正确的自定义布局。

简而言之,如果您要覆盖第三方库的适配器并为适配器指定自己的布局xml,请务必小心。如果项目中的布局与库中的文件名相同,则可能会遇到一个非常难以找到的错误!

答案 13 :(得分:2)

从布局资源设置活动内容。 即,setContentView(R.layout.basicXml);。

答案 14 :(得分:2)

除了上述解决方案,您还要确保 tools:context=".TakeMultipleImages" 在布局中,mainfest.xml文件中的值相同:
android:name=".TakeMultipleImages"表示相同的活动元素。 使用复制和粘贴创建新活动时会发生这种情况

答案 15 :(得分:2)

就我而言,我使用的是ExpandableListView,并设置了android:transcriptMode="normal"。这导致可扩展组中的少数子项消失,并且当我使用滚动列表时,我曾经得到NULL异常。

答案 16 :(得分:2)

我有同样的问题,但我认为值得与你们分享。 如果必须在自定义布局中查找ViewById,例如:

public class MiniPlayerControllBar extends LinearLayout {
    //code
}

你无法在构造函数中获取视图。 您应该在视图充气后调用findViewById。 他们是一种可以覆盖onFinishInflate

的方法

答案 17 :(得分:2)

对我来说,我有两个xml布局用于同一个活动 - 一个在纵向模式,一个在横向。当然,我已经更改了横向xml中对象的id,但忘记了在纵向版本中进行相同的更改。确保你改变一个你对另一个xml做同样的事情,否则你不会得到错误,直到你运行/调试它并且它找不到你没有改变的id。哦,愚蠢的错误,你为什么要这样惩罚我?

答案 18 :(得分:2)

只是想在这里抛出我的具体案例。可能会帮助某人下线。

我在我的Android UI XML中使用了这样的指令:

家长观点:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="home_phone"
    android:background="@color/colorPrimary">

    ...

    <include
        layout="@layout/retry_button"
        android:visibility="gone" />

子视图(retry_button):

<com.foo.RetryButton
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/retry"
    android:layout_gravity="center"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="140dp">

.findViewById(R.id.retry)将始终返回null。但是,如果我将ID从子视图移动到include标记,它就会开始工作。

固定父母:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="home_phone"
    android:background="@color/colorPrimary">

    ...

    <include
        layout="@layout/retry_button"
        android:id="@+id/retry"
        android:visibility="gone" />

修正儿童:

<com.foo.RetryButton
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_gravity="center"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="140dp">

答案 19 :(得分:1)

在我的情况下,我已经夸大了布局,但子视图返回null。最初我有这个:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_history);

    footerView = ((LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.listview_footer, null, false);
    pbSpinner = (ProgressBar) findViewById(R.id.pbListviewFooter);
    tvText = (TextView) findViewById(R.id.tvListviewFooter);
    ...
}

然而,当我将其改为以下时,它起作用了:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_history);

    footerView = ((LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.listview_footer, null, false);
    pbSpinner = (ProgressBar) footerView.findViewById(R.id.pbListviewFooter);
    tvText = (TextView) footerView.findViewById(R.id.tvListviewFooter);
    ...
}

关键是要专门引用已经膨胀的布局以获取子视图。也就是说,添加footerView

  • footerView .findViewById ...

答案 20 :(得分:1)

我已经尝试了上述所有内容都没有工作..所以我必须让我的 ImageView静态 public static ImageView texture;然后texture = (ImageView) findViewById(R.id.texture_back);,我不认为这是虽然这是一个很好的方法,但这确实适用于我的情况:)

答案 21 :(得分:0)

我的解决方法是清理项目。

答案 22 :(得分:0)

如果你在片段中,findViewById也可以返回null。如下所述:findViewById in Fragment

您应该调用getView()以返回片段内的顶级视图。然后你可以找到布局项目(按钮,文本视图等)

答案 23 :(得分:0)

充满布局! (包含id)

在我的情况下,findViewById()返回null,因为编写元素的布局没有膨胀......

EG。 fragment_layout.xml

Random

findViewById(R.id.listview)返回null,因为我没有这样做 inflater.inflate(R.layout.fragment_layout,...,...); 在它之前。

希望这个答案可以帮助所有人。

答案 24 :(得分:0)

根据我的经验,在OnDestroyView之后调用代码时(当片段位于后台堆栈时),似乎也会发生这种情况。如果要更新BroadCastReceiver输入的UI,您应该检查是否是这样的。

答案 25 :(得分:0)

在我的情况下,当我将调用从父对象移动到由父对象实例化的适配器对象时,findViewById返回null。在尝试了此处未列出的技巧之后,我将findViewById移回了父对象,并在实例化适配器对象期间将结果作为参数传递。 例如,我是在父对象中完成的:

 Spinner hdSpinner = (Spinner)view.findViewById(R.id.accountsSpinner);

然后我在创建适配器对象的过程中将hdSpinner作为参数传递:

  mTransactionAdapter = new TransactionAdapter(getActivity(),
        R.layout.transactions_list_item, null, from, to, 0, hdSpinner);

答案 26 :(得分:0)

它崩溃了,因为我的活动ID中的一个字段与另一个活动中的ID匹配。我通过提供唯一的ID对其进行了修复。

在我的loginActivity.xml密码字段中,ID为“ password”。在我的注册活动中,我只是通过提供id r_password对其进行了修复,然后它返回的不是null对象:

password = (EditText)findViewById(R.id.r_password);

答案 27 :(得分:0)

当我尝试为ListView创建自定义视图时,我遇到了类似的问题。

我只是通过以下方法解决了它:

public View getView(int i, View view, ViewGroup viewGroup) {

    // Gets the inflater
    LayoutInflater inflater = LayoutInflater.from(this.contexto);

    // Inflates the layout
    ConstraintLayout cl2 = (ConstraintLayout) 
    inflater.inflate(R.layout.custom_list_view, viewGroup, false);

    //Insted of calling just findViewById, I call de cl2.findViewById method. cl2 is the layout I have just inflated. 
     TextView tv1 = (TextView)cl2.findViewById(cl2);

答案 28 :(得分:0)

调试和发现问题的方法:

  • 注释掉您活动中的所有findViewById。
  • 注释掉onCreate和setContentView之外的所有内容
  • 运行项目,查看是否设置了任何布局

就我而言,我在我的应用程序模块和库模块中都使用了activity_main.xml。因此,当我执行上述步骤时,不是我在库中设计的布局,而是应用模块内部的布局膨胀了。

所以我将activity_main.xml文件名更改为activity_main_lib.xml。

因此请确保您在整个项目中没有重复的布局名称