访问 onCreate()中的视图的 NullPointerException

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

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

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

Layout 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>
22813 次浏览

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

视图在片段布局(fragment_main.xml)中,而不在活动布局(activity_main.xml)中。onCreate()处于生命周期的早期阶段,无法在活动视图层次结构中找到它,因此返回一个 null。在 null上调用方法会导致 NPE。

首选的解决方案是将代码移动到片段 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;
}

As a side note, the fragment layout will eventually be a part of the activity view hierarchy and discoverable with activity findViewById() but only after the fragment transaction has been run. Pending fragment transactions get executed in super.onStart() after onCreate().

因为您已经在 fragment_main.xml中声明了您的 View,所以请移动那段代码,您可以在这段代码的 onCreateView()方法中获得 NPE。 这应该能解决问题。

同意,这是一个典型的错误,因为当人们开始开发 Android 时,他们通常并不真正理解片段是如何工作的。为了减轻困惑,我创建了一个简单的示例代码,我最初在 应用程序在 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>

例子片段:

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 来显示一个片段,并处理该片段中的事件。以及如何与包含的活动进行通信。

尝试使用 OnStart()方法

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

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

Declare click listener on view by anyView.setOnClickListener(this);

Add the following in your 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 文件名称是“片段 _ main.xml”,这意味着您正在尝试获取未显示的片段 _ main.xml 文件的视图,因此它提供了 null 指针异常。更改代码,例如:

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

您正在尝试访问 onCreate()中的 UI 元素,但是现在访问它们还为时过早,因为在片段中可以用 onCreateView()方法创建视图。 And onActivityCreated() method is reliable to handle any actions on them, since activity is fully loaded in this state.

在调用 findViewById()onCreate()onCreateView()方法之后,我使用相同的 NullPointerException初始化侦听器。

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

希望能有所帮助。

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

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

视图“ something”在片段中而不是在活动中,因此您必须在片段类中访问它,而不是在活动中访问它

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

你要记住一件重要的事: 当声明变量并试图在为其赋值之前检索其值时,会发生 NullPointerException。

Use OnViewCreated () Method whenever using or calling views from fragments.

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

最流行的查找视图库,几乎每个开发人员都在使用它。

蝴蝶刀

正如我可以他们的足够的答案解释寻找观点与适当的方法论。但是如果你是 Android 开发者,并且每天都要经常编写代码,那么你可以使用“黄油刀”,这样可以节省很多查找视图的时间,而且你也不需要为此编写代码。只需要2-3个步骤,你就可以在毫秒内查找视图。

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

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

Add plugin for butter knife:

File -> Settings -> plugins->

然后搜索 安卓系统蝴蝶刀 Zelezny并安装插件,重新启动你的工作室,你就完成了。

Now just go to Oncreate method of your activity and right click on your layout_name and tap on generate button and select butterknife injection option and your views references will be automatically created like mention below:

    @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;