可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This is a canonical question for a problem frequently posted on StackOverflow.
I'm following a tutorial. I've created a new activity using a wizard. I get NullPointerException
when attempting to call a method on View
s obtained with findViewById()
in my activity onCreate()
.
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(); } }
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>
回答1:
The tutorial is probably outdated, attempting to create an activity-based UI instead of the fragment-based UI preferred by wizard-generated code.
The view is in the fragment layout (fragment_main.xml
) and not in the activity layout (activity_main.xml
). onCreate()
is too early in the lifecycle to find it in the activity view hierarchy, and a null
is returned. Invoking a method on null
causes the NPE.
The preferred solution is to move the code to the fragment onCreateView()
, calling findViewById()
on the inflated fragment layout 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; }
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()
.
回答2:
Try OnStart()
method and just use
View view = getView().findViewById(R.id.something);
or Declare any View using getView().findViewById
method in onStart()
Declare click listener on view by anyView.setOnClickListener(this);
回答3:
Agreed, this is a typical error because people often don't really understand how Fragments work when they begin working on Android development. To alleviate confusion, I created a simple example code that I originally posted on Application is stopped in android emulator , but I posted it here as well.
An example is the following:
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>
And that should be a valid example, it shows how you can use an Activity to display a Fragment, and handle events in that Fragment. And also how to communicate with the containing Activity.
回答4:
Try to shift your accessing views to the onViewCreated method of fragment because sometimes when you try to access the views in onCreate method they are not rendered at the time resulting null pointer 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(); } }
回答5:
The view "something" is in fragment and not in activity, so instead of accessing it in activity you must access it in the fragment class like
In 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; }
回答6:
You are trying to access UI elements in the onCreate()
but , it is too early to access them , since in fragment views can be created in onCreateView()
method. And onActivityCreated()
method is reliable to handle any actions on them, since activity is fully loaded in this state.
回答7:
Since you have declared your View in the fragment_main.xml
,move that piece of code where you get the NPE in the onCreateView()
method of the fragment. This should solve the issue.
回答8:
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>
回答9:
in the posted code above in the question there is a problem : you are using R.layout.activity_main in oncreate method, but the xml files name is "fragment_main.xml" , means you are trying to get the view of fragment_main.xml file which is not being shown so it gives null pointer exception. change the code like :
@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(); } }
回答10:
You have to remember important thing is : NullPointerException occurs when you have declared your variable and trying to retreive its value before assigning value to it.
回答11:
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) }
回答12:
I've got the same NullPointerException
initializing a listener after calling findViewById()
onCreate()
and onCreateView()
methods.
But when I've used the onActivityCreated(Bundle savedInstanceState) {...}
it works. So, I could access the GroupView
and set my listener.
I hope it be helpful.