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.xml
中onCreateView()
方法中的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,并试图检索之前,它的价值检索。