首页 文章

findViewByID返回null

提问于
浏览
217

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

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

我从其他人那里了解到, View.findViewByIdActivity.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 . Doing this, my Activity works fine. 所以也许是因为 Activity.findViewByIdView.findViewById 的差异 . 所以我在本地存储了传递给海关视图构造函数的上下文并尝试:

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

其中也返回 null .

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

那么我做错了什么?

我会感激任何评论 .

27 回答

  • 0

    返回null

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

  • 86

    可能在调用 setContentView 之前调用 findViewById ?如果是这种情况,请尝试调用 findViewById AFTER 调用 setContentView

  • 243

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

  • 12

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

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

    它总是空的 . 事实证明,在 onCreate 构造函数中,我实例化的不是 main2 ,而是另一个 . 我有:

    setContentView(R.layout.main);
    

    代替

    setContentView(R.layout.main2);
    

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

  • 0

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

    • 确保在 findViewById() 之前调用 setContentView()

    • 确保您想要的 id 位于您提供给 setContentView() 的视图或布局中

    • 确保 id 不会在不同的布局中意外重复

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

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

    • 使用 FrameLayout 替换每个自定义视图,其具有与自定义视图相同的布局属性 . 给它一个合适的 id ,比如 frame_for_custom_view .

    • onCreate

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

    它将自定义视图放在框架中 .

  • 8

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

    这是错误的

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

    这是对的

    public CameraSurfaceView(Context context, AttributeSet attrs) {
            super(context,attrs);
    }
    
  • 5
    @Override
    protected void onStart() {
             // use findViewById() here instead of in onCreate()
        }
    
  • 2

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

    我尝试在我的子视图和组视图中使用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 .

  • 2

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

  • 3

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

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

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

  • 12

    在我的特定情况下,我试图向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);
    
  • 2

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

  • 2

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

  • 6

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

  • 0

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

  • 2

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

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

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

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

  • 1

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

  • 0

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

    public class MiniPlayerControllBar extends LinearLayout {
        //code
    }
    

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

  • 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">
    
  • 0

    在我的情况下,我已经夸大了布局,但子视图返回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 ......
  • 0

    我已经尝试了上面所有的一切都没有工作..所以我不得不让我的 ImageView static public static ImageView texture; 然后 texture = (ImageView) findViewById(R.id.texture_back); ,我不是一个很好的方法,但这真的适用于我的情况:)

  • 3

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

  • 4

    充满了布局! (包含id)

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

    例如 . fragment_layout.xml

    <ListView
    android:id="@+id/listview">
    

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

    希望这个答案可以帮助你们所有人 .

  • 1

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

  • 2

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

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

  • 14

    在我的例子中,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);
    
  • 128

    它崩溃了,因为我的活动ID中的一个字段与另一个活动中的id匹配 . 我通过给出一个唯一的ID来修复它 .

    在我的loginActivity.xml中,密码字段id是“password” . 在我的注册活动中,我只是通过给出id r_password来修复它,然后它返回的不是null对象:

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

相关问题