NullPointerException, що отримує доступ до переглядів у onCreate ()


114

Це канонічне питання щодо проблеми, яка часто розміщується в StackOverflow.

Я стежу за підручником. Я створив нову діяльність за допомогою майстра. Я отримую NullPointerExceptionпри спробі викликати метод на Views, отриманий 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>

Відповіді:


70

Підручник, ймовірно, застарів, намагаючись створити інтерфейс, що базується на діяльності, замість інтерфейсу на основі фрагментів, який надає перевагу коду, створеному майстром.

Перегляд знаходиться у макеті фрагмента ( fragment_main.xml), а не у макеті діяльності ( activity_main.xml). onCreate()занадто рано в життєвому циклі, щоб знайти його в ієрархії подання активності, і nullповертається a . Викликати метод на nullпричини НПЕ.

Кращим рішенням є переміщення коду до фрагмента 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().


Частина findViewById повинна бути в OnActivityCreate.
Zar E Ahmer

@Nepster Це може бути, але не обов’язково.
laalto

Інколи діяльність ще не приєднана до фрагменту.
Zar E Ahmer

1
@Nepster і тому закликають findViewById()на rootViewі не від діяльності.
laalto

10

Спробуйте OnStart()метод і просто використовуйте

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

або оголосити будь-який вид перегляду за допомогою getView().findViewByIdметоду вonStart()

Оголосити слухача кліків на перегляді anyView.setOnClickListener(this);


Для мене це було корисно, оскільки я намагався отримати доступ до представлення братів та сестер всередині onCreateView фрагмента, де фрагмент був оголошений у xml. Погляди братів і сестер все ще були недійсними в onCreateView, тому що батько ще не закінчив надувати, але він почав:
Даніель Вілсон,

3

Спробуйте перенести свої представлення доступу до фрагменту методу onViewCreate, оскільки іноді, коли ви намагаєтеся отримати доступ до представлень у методі 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();
    }
 }

2

Погоджено, це типова помилка, оскільки люди часто не дуже розуміють, як працюють фрагменти, коли вони починають працювати над розробкою 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>

І це має бути дійсним прикладом, він показує, як можна використовувати Діяльність для відображення фрагмента та обробляти події в цьому Фрагменті. А також як спілкуватися із вмістом, що містить вміст.


1
У цьому прикладі використовується бібліотека android-support-v4 для FragmentActivity та менеджер фрагментів підтримки.
EpicPandaForce

1
ще більш повний приклад можна знайти на stackoverflow.com/questions/24840509 / ...
EpicPandaForce

1
Хоча вам слід використовувати Ottoдля спілкування замість зворотних дзвінків і використовувати Butterknifeдля введення подань.
EpicPandaForce

2

Перегляд "щось" знаходиться в фрагменті, а не в діяльності, тому замість доступу до нього в діяльності ви повинні отримати доступ до цього класу фрагментів, як

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

2

Ви намагаєтеся отримати доступ до елементів інтерфейсу в, onCreate()але доступ до них зарано, оскільки в фрагментах представлення можуть створюватися onCreateView()методом. І onActivityCreated()метод надійно обробляє будь-які дії над ними, оскільки діяльність повністю завантажена в цьому стані.


1

Додайте наступне у свою Activity_main.xml

<fragment
    android:id="@+id/myFragment"
    android:name="packagename.MainActivity$PlaceholderFragment"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >
</fragment>

0

Оскільки ви заявили про свій погляд у розділі " fragment_main.xmlПеремістіть" той фрагмент коду, де ви отримаєте NPE в onCreateView()методі фрагмента. Це має вирішити питання.


0

у розміщеному коді вище у питанні є проблема: ви використовуєте 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();
    }
}

0

Ви повинні пам’ятати важливе: NullPointerException виникає, коли ви оголосили змінну і намагаєтеся отримати її значення, перш ніж присвоїти їй значення.


0

Використовуйте метод onViewCreate () щоразу, коли ви використовуєте або викликаєте погляди з фрагментів.

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

0

У мене ж NullPointerExceptionініціалізація слухача після виклику findViewById() onCreate()та onCreateView()методів.

Але коли я використав це, onActivityCreated(Bundle savedInstanceState) {...}він працює. Отже, я міг отримати доступ до GroupViewсвого слухача та встановити його.

Я сподіваюся, що це буде корисно.


0

Найпопулярніша бібліотека для пошуку переглядів, яку використовує майже кожен розробник.

Масляний ніж

Наскільки я можу їх достатньо відповідей, що пояснюють пошук поглядів за допомогою відповідної методології. Але якщо ви розробник андроїдів і кодуєте часто на щоденній основі, тоді ви можете використовувати масло-нож, який економить багато часу на пошуку переглядів, і ви не маєте для цього коду написання. За 2-3 кроки ви можете знайти перегляди в мілісекундах .

Додайте залежність у ступінь рівня програми:

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

Додати плагін для ножа для масла:

File -> Settings -> plugins-> 

Потім знайдіть Android ButterKnife Zelezny та встановіть плагін і перезапустіть свою студію, і ви все з цим готові.

Тепер просто перейдіть до методу Oncreate вашої діяльності та клацніть правою кнопкою миші на вашій імені макета і натисніть кнопку створення і виберіть варіант введення масляного ножа, і посилання на ваш погляд автоматично будуть створені, як згадується нижче:

    @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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.