NullPointerException访问onCreate()中的视图


114

对于经常在StackOverflow上发布的问题,这是一个规范的问题。

我正在学习教程。我使用向导创建了一个新活动。我得到NullPointerException试图调用一个方法时,View与s的粘度findViewById()在我的活动onCreate()

活动内容onCreate()

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

    View something = findViewById(R.id.something);
    something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment()).commit();
    }
}

布局XML(fragment_main.xml):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="packagename.MainActivity$PlaceholderFragment" >

    <View
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:id="@+id/something" />

</RelativeLayout>

Answers:


70

本教程可能已过时,试图创建基于活动的UI,而不是向导生成的代码首选的基于片段的UI。

该视图位于片段布局(fragment_main.xml)中,而不位于活动布局(activity_main.xml)中。onCreate()在生命周期中为时过早,无法在活动视图层次结构中找到它,并null返回a。调用on null会导致NPE。

首选的解决方案是将代码移动到片段onCreateView(),并调用findViewById()膨胀的片段布局rootView

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
  View rootView = inflater.inflate(R.layout.fragment_main, container,
      false);

  View something = rootView.findViewById(R.id.something); // not activity findViewById()
  something.setOnClickListener(new View.OnClickListener() { ... });

  return rootView;
}

附带说明,片段布局最终将成为活动视图层次结构的一部分,并且可以在活动中发现,findViewById()但仅在片段事务已运行之后。待处理的片段事务在super.onStart()之后执行onCreate()


findViewById部分应位于onActivityCreated中。
Zar E Ahmer '16

@Nepster可以但不一定要。
laalto

有时活动尚未附加到片段。
Zar E Ahmer '16

1
@Nepster这就是为什么叫findViewById()rootView,而不是活动。
laalto

10

尝试OnStart()方法并使用

View view = getView().findViewById(R.id.something);

或使用中的getView().findViewById方法声明任何视图onStart()

声明查看者的点击监听器 anyView.setOnClickListener(this);


对我来说,这很有用,因为我试图访问片段的onCreateView中的同级视图,该片段在xml中声明。兄弟视图在onCreateView中仍然为空,因为父级尚未完成充气,但是在onStart中它们具有:)
Daniel Wilson

3

尝试将访问的视图转移到片段的onViewCreated方法,因为有时当您尝试在onCreate方法中访问视图时,它们在出现空指针异常时不会被呈现。

 @Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
     View something = findViewById(R.id.something);
     something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE

     if (savedInstanceState == null) {
           getSupportFragmentManager().beginTransaction()
            .add(R.id.container, new PlaceholderFragment()).commit();
    }
 }

2

同意,这是一个典型的错误,因为人们在开始进行Android开发时通常并不真正了解Fragments是如何工作的。为了减轻混乱,我创建了一个简单的示例代码,最初将其发布在Application上,该代码已在android emulator中停止,但我也将其发布在此处。

下面是一个示例:

public class ContainerActivity extends FragmentActivity implements ExampleFragment.Callback
{
    @Override
    public void onCreate(Bundle saveInstanceState)
    {
        super.onCreate(saveInstanceState);
        this.setContentView(R.layout.activity_container);
        if (saveInstanceState == null)
        {               
             getSupportFragmentManager().beginTransaction()
                .add(R.id.activity_container_container, new ExampleFragment())
                .addToBackStack(null)
             .commit();
        }
        getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener()
        {
            public void onBackStackChanged()
            {
                int backCount = getSupportFragmentManager().getBackStackEntryCount();
                if (backCount == 0)
                {
                    finish();
                }
            }
        });
    }

    @Override
    public void exampleFragmentCallback()
    {
        Toast.makeText(this, "Hello!", Toast.LENGTH_LONG).show();
    }
}

activity_container.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <FrameLayout
        android:id="@+id/activity_container_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

ExampleFragment:

public class ExampleFragment extends Fragment implements View.OnClickListener
{
    public static interface Callback
    {
        void exampleFragmentCallback();
    }

    private Button btnOne;
    private Button btnTwo;
    private Button btnThree;

    private Callback callback;

    @Override
    public void onAttach(Activity activity)
    {
        super.onAttach(activity);
        try
        {
            this.callback = (Callback) activity;
        }
        catch (ClassCastException e)
        {
            Log.e(this.getClass().getSimpleName(), "Activity must implement Callback interface.", e);
            throw e;
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View rootView = inflater.inflate(R.layout.fragment_example, container, false);

        btnOne = (Button) rootView.findViewById(R.id.example_button_one);
        btnTwo = (Button) rootView.findViewById(R.id.example_button_two);
        btnThree = (Button) rootView.findViewById(R.id.example_button_three);

        btnOne.setOnClickListener(this);
        btnTwo.setOnClickListener(this);
        btnThree.setOnClickListener(this);
        return rootView;
    }

    @Override
    public void onClick(View v)
    {
        if (btnOne == v)
        {
            Toast.makeText(getActivity(), "One.", Toast.LENGTH_LONG).show();
        }
        else if (btnTwo == v)
        {
            Toast.makeText(getActivity(), "Two.", Toast.LENGTH_LONG).show();
        }
        else if (btnThree == v)
        {
            callback.exampleFragmentCallback();
        }
    }
}

fragment_example.xml:

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

        <Button
            android:id="@+id/example_button_one"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="30dp"
            android:text="@string/hello" 
            android:layout_marginLeft="20dp"
            android:layout_marginRight="20dp"/>

        <Button
            android:id="@+id/example_button_two"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/example_button_one"
            android:layout_alignRight="@+id/example_button_one"
            android:layout_below="@+id/example_button_one"
            android:layout_marginTop="30dp"
            android:text="@string/hello" />

        <Button
            android:id="@+id/example_button_three"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/example_button_two"
            android:layout_alignRight="@+id/example_button_two"
            android:layout_below="@+id/example_button_two"
            android:layout_marginTop="30dp"
            android:text="@string/hello" />

</RelativeLayout>

那应该是一个有效的示例,它显示了如何使用“活动”来显示片段,以及如何处理该片段中的事件。以及如何与包含的活动进行通信。


1
此示例将android-support-v4库用于FragmentActivity和支持片段管理器。
EpicPandaForce 2014年


1
虽然您应该使用Otto通讯而不是回调,并使用它Butterknife来注入视图。
EpicPandaForce'3

2

视图“某物”在片段中而不在活动中,因此,除了在活动中访问它之外,您还必须在片段类中对其进行访问,例如

在PlaceholderFragment.class中

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_main, container,
  false);

View something = root .findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... });

return root;
}

2

您正在尝试在onCreate()but中访问UI元素,现在访问它们还为时过早,因为可以在onCreateView()method中创建片段视图。和onActivityCreated()方法是可靠的处理对他们的任何行动,因为活动是在这种状态下满载。


1

在您的activity_main.xml中添加以下内容

<fragment
    android:id="@+id/myFragment"
    android:name="packagename.MainActivity$PlaceholderFragment"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >
</fragment>


0

在上面问题中的已发布代码中,有一个问题:您在oncreate方法中使用R.layout.activity_main,但是xml文件的名称为“ fragment_main.xml”,这意味着您正在尝试获取fragment_main.xml文件的视图它没有显示,所以它给出了空指针异常。更改代码,例如:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.fragment_main);// your xml layout ,where the views are

    View something = findViewById(R.id.something);
    something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE

    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment()).commit();
    }
}


0

每当使用或从片段调用视图时,请使用onViewCreated()方法。

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
      View v = view.findViewById(R.id.whatever)
}

0

我已经得到了同样的NullPointerException呼吁后初始化监听器findViewById() onCreate()onCreateView()方法。

但是当我使用onActivityCreated(Bundle savedInstanceState) {...}它的时候就可以了。因此,我可以访问GroupView并设置我的监听器。

希望对您有所帮助。


0

查找视图的最受欢迎的库,几乎每个开发人员都使用该库。

牛油刀

就我所能提供的足够的答案,他们用正确的方法解释了寻找观点的方法。但是,如果您是android开发人员,并且每天都经常编写代码,则可以使用黄油刀,这样可以节省很多时间来查找视图,而您无需编写代码,只需2-3步,您就可以在几毫秒内找到视图。

在应用程序级别gradle中添加依赖项:

implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

添加黄油刀插件:

File -> Settings -> plugins-> 

然后搜索Android ButterKnife Zelezny并安装插件,然后重新启动您的工作室即可。

现在只需转到您活动的Oncreate方法,然后右键单击您的layout_name并点击“生成”按钮,然后选择“黄油刀注入”选项,您的视图引用将自动创建,如下所述:

    @BindView(R.id.rv_featured_artist)
    ViewPager rvFeaturedArtist;
    @BindView(R.id.indicator)
    PageIndicator indicator;
    @BindView(R.id.rv_artist)
    RecyclerView rvArtist;
    @BindView(R.id.nsv)
    NestedScrollingView nsv;
    @BindView(R.id.btn_filter)
    Button btnFilter;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.