NullPointerException - доступ к представлениям в onCreate()
Это канонический вопрос для проблемы, часто заданной в StackOverflow.
Я следую учебнику. Я создал новое действие с помощью мастера. Я получаю NullPointerException
при попытке вызвать метод на View
, полученный с помощью 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>
Ответы
Ответ 1
Учебник, вероятно, устарел, пытаясь создать пользовательский интерфейс на основе действий вместо пользовательского интерфейса на основе фрагментов, который был выбран с помощью кода, созданного с помощью мастера.
Вид находится в макете фрагмента (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;
}
В качестве дополнительной заметки макет фрагмента в конечном итоге станет частью иерархии видов деятельности и обнаруживается с активностью findViewById()
, но только после выполнения транзакции фрагмента. Незавершенные транзакции фрагментов выполняются в super.onStart()
после onCreate()
.
Ответ 2
Попробуйте OnStart()
метод и просто используйте
View view = getView().findViewById(R.id.something);
или Объявить любой вид с помощью метода getView().findViewById
в OnStart()
Объявите прослушивание кликов в режиме просмотра anyView.setOnClickListener(this);
Ответ 3
Согласовано, это типичная ошибка, потому что люди часто не понимают, как работают Фрагменты, когда они начинают работать над разработкой 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>
И это должен быть допустимый пример, он показывает, как вы можете использовать Activity для отображения фрагмента и обрабатывать события в этом фрагменте. А также, как связаться с содержащейся активностью.
Ответ 4
Попытайтесь перенести свои просмотры доступа на метод 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();
}
}
Ответ 5
Вид "что-то" находится в фрагменте, а не в активности, поэтому вместо доступа к нему в действии вы должны получить к нему доступ в классе фрагментов, например
В 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
Вы пытаетесь получить доступ к элементам пользовательского интерфейса в onCreate(), но слишком рано обращаться к ним, поскольку в представлениях фрагментов может быть создан метод onCreateView().
Метод onActivityCreated() надежен для обработки любых действий на них, поскольку активность полностью загружена в этом состоянии.
Ответ 7
Поскольку вы объявили свой вид в fragment_main.xml
, переместите этот фрагмент кода, где вы получаете NPE в методе onCreateView()
фрагмента.
Это должно решить проблему.
Ответ 8
Добавьте в свой 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
в размещенном выше коде в вопросе возникает проблема:
вы используете R.layout.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();
}
}
Ответ 10
У меня есть тот же NullPointerException, инициализирующий слушателя после вызова методов findViewById onCreate и onCreateView.
Но когда я использовал onActivityCreated (Bundle savedInstanceState) {...}, он работает. Таким образом, я мог получить доступ к GroupView и установить прослушиватель.
Надеюсь, это будет полезно.
Ответ 11
Вы должны помнить, что важно:
NullPointerException возникает, когда вы объявили свою переменную и пытаетесь вернуть ее значение, прежде чем назначать ему значение.
Ответ 12
Используйте метод onViewCreated() при каждом использовании или вызове видов из фрагментов.
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
View v = view.findViewById(R.id.whatever)
}