空指针异常 - findViewById()

59

有人可以帮我找出这个程序的问题吗?在onCreate()方法中,findViewById()返回所有id的值都为null,导致后面出现了空指针异常。我无法弄清楚为什么findViewById()找不到视图,请问有什么建议吗?

这是主要的代码:

public class MainActivity extends Activity {

    ViewPager pager;
    MyPagerAdapter adapter;
    LinearLayout layout1, layout2, layout3;

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

        layout1 = (LinearLayout) findViewById(R.id.first_View);
        layout2 = (LinearLayout) findViewById(R.id.second_View);
        layout3 = (LinearLayout) findViewById(R.id.third_View);

        adapter = new MyPagerAdapter();
        pager = (ViewPager) findViewById(R.id.main_pager);
        pager.setAdapter(adapter);
    }

    private class MyPagerAdapter extends PagerAdapter
    {

        @Override
        public int getCount() { 
            return 3;
        }

        @Override
        public Object instantiateItem(ViewGroup collection, int position) {

            LinearLayout l = null;

            if (position == 0 )
            {
                l = layout1;
            }
            if (position == 1)
            {
                l = layout2;
            }

            if (position == 2)
            {
                l = layout3;
            }
                collection.addView(l, position);
                return l;
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return (view==object);
        }

         @Override
         public void destroyItem(ViewGroup collection, int position, Object view) {
                 collection.removeView((View) view);
         }
    }
}

相关的XML文件:

activity_main布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:orientation="vertical"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:background="#a4c639">


    <android.support.v4.view.ViewPager
                        android:layout_width="match_parent" 
                        android:layout_height="match_parent" 
                        android:id="@+id/main_pager"/>
</LinearLayout>

首个活动布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/first_View">

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_world" />

<Button
    android:id="@+id/button1"
    style="?android:attr/buttonStyleSmall"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Button" />

</LinearLayout>

activity_second布局:

 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/second_View">

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_world" />

</LinearLayout>

并且是 activity_third 布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/third_View">

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_world" />

</LinearLayout>
12个回答

92

findViewById()如果存在在你提供的布局中(通过setContentView()方法),它会返回一个View,否则返回null。注意,如果你没有调用setContentView()或者没有有效的视图可以在findViewById()上找到,则findViewById()将始终返回null,直到你调用了setContentView()

这也意味着顶层变量会触发NPE异常,因为它们在onCreate()方法之前被调用,也就是在setContentView()方法之前。请参阅activity生命周期

例如,如果您调用setContentView(R.layout.activity_first);,然后调用findViewById(R.id.first_View);,它将返回您的布局中的一个 View。

但是,如果您在调用setContentView()之前调用findViewById(R.id.second_View);,它将返回null,因为在您的activity_first.xml布局中没有名为@+id/second_View的视图。


我已将所有布局加入到主布局中,现在不再有空指针异常了。感谢您的提示。 - user2629828
7
当我在当前显示视图以外的另一个视图上使用它时,那个视图出现了。为了克服这种不良行为,我按照以下方式引用了该视图而没有使用setContentView。layout1 =(LinearLayout)View.inflate(this,R.layout.first_View,null);然后要访问其中的任何内容,我可以使用Button button =(Button)layout1.findViewById(R.id.button1);只是添加一下,希望对某些人有所帮助。 - isuru chathuranga
1
为什么?强制我们有什么好处? - Niklas Rosencrantz
那么,如何在“setContentView()”中未提供资源的情况下包含该资源呢? - Alston

3

强调已添加

对于Activity类内的情况。

Activity.findViewById(int id)

onCreate(Bundle)中处理的XML中查找使用id属性标识的视图。


否则,如Fragment、Adapter、从LayoutInflater中获取的View等。

View.findViewById(int id)

查找具有给定id的子视图。如果此视图具有给定的id,则返回此视图。


无论哪种情况,

返回
如果找到视图,则返回该视图或否则返回null


现在,请重新检查您的XML文件。确保在setContentViewinflater.inflate中放入了正确的值。

对于Activity,在setContentView之后调用findViewById

然后,请确保在该布局中使用android:id="@+id/..."查找您要查找的视图。确保+位于@+id处,这将将资源添加到R.id值中,以确保您可以从Java中找到它。


2
你正在尝试获取的视图在你的activity_main布局中未定义。你需要通过编程方式填充你想要添加到页面中的视图。
@Override
public Object instantiateItem(ViewGroup collection, int position) {
    LinearLayout l = null;

    if (position == 0) {
        l = (LinearLayout) View.inflate(this, R.layout.activity_first, null);
    }
    if (position == 1) {
        l = (LinearLayout) View.inflate(this, R.layout.activity_second, null);
    }
    if (position == 2) {
        l = (LinearLayout) View.inflate(this, R.layout.activity_third, null);
    }

    collection.addView(l, position);
    return l;
}

你如何访问MainActivity中的视图? - Denny

2
有时候你需要在Eclipse中清理你的项目(Project - Clean..)。

这对我解决了问题 - 手动步骤很荒谬,而且错误会影响ID查找。我以为机器总是很逻辑的 - 到底什么能够以这种方式破坏代码?! - Razvan_TK9692

1
在我的情况下,这是我的一个愚蠢错误。我在OnCreate方法中编写了代码,但它在setContentView代码行的上面。一旦我将我的代码移动到这行代码下面,应用程序就开始正常工作了。
setContentView(R.layout.activity_main);

1
在访问这些视图之前,请将它们添加到分页适配器中。
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    adapter = new MyPagerAdapter();
    pager = (ViewPager) findViewById(R.id.main_pager);
    pager.setAdapter(adapter);

    layout1 = (LinearLayout) findViewById(R.id.first_View);
    layout2 = (LinearLayout) findViewById(R.id.second_View);
    layout3 = (LinearLayout) findViewById(R.id.third_View);

}

在页面适配器中:
public Object instantiateItem(View collection, int position) {
    if(position == 0){
        View layout = inflater.inflate(R.layout.activity_first, null);

        ((ViewPager) collection).addView(layout);

        return layout;
    } 
    ... and so forth.

}

从这里你可以通过 findViewById 访问它们。

0
使用适配器来填充布局,根据位置可以查找视图。
override fun instantiateItem(collection: ViewGroup, position: Int) : ViewGroup {
    val inflater = LayoutInflater.from(mContext)
    val layout = inflater.inflate(mData[position], collection, false) as ViewGroup

    if(position == your_position) {
       val nameOfField: TextView = layout.findViewById(R.id.item_id)
    }

0

@Warlock 上面所说的是正确的,你应该以正确的方式初始化 LinearLayout layout1、layout2 和 layout3:

LinearLayout layout1 = (LinearLayout) View.inflate(this, R.layout.first_View, null);
LinearLayout layout2 = (LinearLayout) View.inflate(this, R.layout.second_View, null);
LinearLayout layout3 = (LinearLayout) View.inflate(this, R.layout.third, null);

希望我的建议能帮到你


0
在Android中,当您在布局集中查找视图时,findViewById(R.id.some_id)是有效的。
也就是说,如果您设置了一个布局,比如:
setContentView(R.layout.my_layout);

视图只能在此布局(my_layout)中找到。

在您的代码中,layout1layout2layout3 都是三个不同的布局,并且它们没有设置到活动中。


0
今天我遇到了这个错误,解决起来非常简单,以至于我“扇了自己一巴掌”。
只需尝试将UI元素添加到您的布局XML文件中,在您的res/layout-port目录中即可!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接