NullPointerException доступ к представлениям в onCreate()
это канонический вопрос для проблемы, часто публикуемой на 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>
13 ответов:
учебник, вероятно, устарел, пытаясь создать пользовательский интерфейс на основе действий вместо пользовательского интерфейса на основе фрагментов, предпочитаемого сгенерированным мастером кодом.
вид находится в макете фрагмента (
fragment_main.xml
) и не в макете активности (activity_main.xml
).onCreate()
слишком рано в жизненном цикле, чтобы найти его в иерархии представлений активности, иnull
возвращается. Вызов метода на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; }
в качестве дополнительной заметки макет фрагмента в конечном итоге станет частью иерархии представлений активности и будет обнаружен с помощью activity
findViewById()
но только после выполнения фрагментарной транзакции. Отложенные фрагментные транзакции выполняются вsuper.onStart()
послеonCreate()
.
попробовать
OnStart()
способ и просто использоватьView view = getView().findViewById(R.id.something);
или объявить любое представление с помощью
getView().findViewById
методonStart()
объявить прослушиватель щелчка на просмотре по
anyView.setOnClickListener(this);
попробуйте перенести доступ к представлениям в метод фрагмента 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(); } }
согласен, это типичная ошибка, потому что люди часто не понимают, как работают фрагменты, когда они начинают работать над разработкой 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>
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>
и это должно быть допустимым примером, он показывает, как вы можете использовать действие для отображения фрагмента и обрабатывать события в этом фрагменте. А также как общаться с содержащей активностью.
представление" что-то " находится во фрагменте, а не в действии, поэтому вместо доступа к нему в действии вы должны получить доступ к нему в классе фрагмента, например
В PlaceholderFragment.класс
@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()
но, это слишком рано, чтобы получить к ним доступ , так как в фрагменте представления могут быть созданы вonCreateView()
метод. ИonActivityCreated()
метод надежен для обработки любых действий на них, так как активность полностью загружается в этом состоянии.
самая популярная библиотека для поиска представлений, которая используется почти каждым разработчиком.
как я могу их достаточно ответов, объясняющих поиск мнений с надлежащей методологией. Но если вы разработчик android и код часто на ежедневной основе, то вы можете использовать butter-knife, который экономит много времени на поиске представлений, и у вас нет кода для него, с помощью 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 и нажмите на кнопку generate и выберите опцию ButterKnife injection, и ваши ссылки на представления будут автоматически созданы как упоминалось ниже:
@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;
добавьте в свой activity_main.xml
<fragment android:id="@+id/myFragment" android:name="packagename.MainActivity$PlaceholderFragment" android:layout_width="wrap_content" android:layout_height="wrap_content" > </fragment>
Так как вы объявили свое мнение в
fragment_main.xml
, переместите этот кусок кода, где вы получаете NPE вonCreateView()
метод фрагмента. Это должно решить проблему.
в опубликованном выше коде в вопросе есть проблема : вы используете R. макет.activity_main в методе oncreate, но имя 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(); } }
вы должны помнить главное : NullPointerException возникает, когда вы объявили свою переменную и пытаетесь вернуть ее значение перед присвоением ему значения.
использовать onViewCreated() метод при использовании или вызове представлений из фрагментов.
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) View v = view.findViewById(R.id.whatever) }
у меня то же самое
NullPointerException
инициализация прослушивателя после вызоваfindViewById()
onCreate()
иonCreateView()
методы.но когда я использовал
onActivityCreated(Bundle savedInstanceState) {...}
это работает. Итак, я мог получить доступ кGroupView
и установить мой слушатель.Я надеюсь, что это будет полезно.