NullPointerException在onCreate()中访问视图

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

我正在学习一个教程。 我已经使用向导创build了一个新的活动。 当我尝试在我的activity onCreate()方法中调用findViewById()方法获得的View的方法时,我得到NullPointerException

Activity 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> 

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

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

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

 @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()活动来发现,但是只有在片段事务运行之后。 挂起片段事务在onCreate()之后的super.onStart()被执行。

尝试OnStart()方法,只是使用

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

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

通过anyView.setOnClickListener(this);声明单击监听器anyView.setOnClickListener(this);

同意,这是一个典型的错误,因为人们通常不了解Fragments在开始Android开发时是如何工作的。 为了减轻混淆,我创build了一个简单的示例代码,我最初发布在应用程序停止在android模拟器 ,但我也发布在这里。

一个例子如下:

 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> 

这应该是一个有效的例子,它显示了如何使用一个活动来显示一个片段,并处理该片段中的事件。 还有如何与包含Activity交stream。

视图“东西”在片段中而不是在活动中,所以不要在活动中访问它,而必须像片段类那样访问它

在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; } 

您尝试访问onCreate()中的UI元素,但是,访问它们为时尚早,因为可以在onCreateView()方法中创build片段视图。 而onActivityCreated()方法在处理任何操作时是可靠的,因为活动在这个状态下被完全加载。

尝试将访问视图切换到片段的onViewCreated方法,因为有时当您尝试访问onCreate方法中的视图时,它们不会在导致空指针exception的时候呈现。

  @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(); } } 

由于您已经在fragment_main.xml声明了视图,因此将fragment_main.xmlonCreateView()方法中的NPE移动到该位置。 这应该解决这个问题。

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

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

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

 @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(); } } 

调用findViewById onCreate和onCreateView方法后,我得到了相同的NullPointerException初始化侦听器。

但是,当我用onActivityCreated (Bundle savedInstanceState){…}它的作品。 所以,我可以访问GroupView并设置我的监听器。

我希望它是有帮助的。

你必须记住的重要的事情是:NullPointerException发生时,你已经声明你的variables,并试图检索之前,它的价值检索。