NullPointerException mengakses tampilan di onCreate ()


114

Ini adalah pertanyaan kanonik untuk masalah yang sering diposting di StackOverflow.

Saya mengikuti tutorial. Saya telah membuat aktivitas baru menggunakan wizard. Saya dapatkan NullPointerExceptionketika mencoba memanggil metode yang Viewdiperoleh dengan findViewById()dalam aktivitas saya onCreate().

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

Tata Letak 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>

Jawaban:


70

Tutorial ini mungkin sudah usang, mencoba membuat UI berbasis aktivitas alih-alih UI berbasis fragmen yang lebih disukai oleh kode yang dihasilkan wizard.

Tampilan berada di fragment layout ( fragment_main.xml) dan bukan di activity layout ( activity_main.xml). onCreate()terlalu awal dalam daur hidup untuk menemukannya dalam hierarki tampilan aktivitas, dan a nulldikembalikan. Memanggil metode nullmenyebabkan NPE.

Solusi yang lebih disukai adalah dengan memindahkan kode ke fragmen onCreateView(), memanggil findViewById()tata letak fragmen yang diluaskan 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;
}

Sebagai catatan tambahan, tata letak fragmen pada akhirnya akan menjadi bagian dari hierarki tampilan aktivitas dan dapat ditemukan dengan aktivitas, findViewById()tetapi hanya setelah transaksi fragmen telah dijalankan. Transaksi fragmen yang tertunda dieksekusi super.onStart()setelahnya onCreate().


Bagian findViewById harus ada di onActivityCreated.
Zar E Ahmer

@Nepster Bisa jadi tapi tidak harus.
laalto

Terkadang aktivitas belum dilampirkan ke fragmen.
Zar E Ahmer

1
@Nepster Dan yang ini mengapa menelepon findViewById()di rootViewdan bukan pada aktivitas.
laalto

10

Coba OnStart()metode dan gunakan saja

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

atau Deklarasikan Tampilan apa pun menggunakan getView().findViewByIdmetode dalamonStart()

Deklarasikan pemroses klik pada tampilan oleh anyView.setOnClickListener(this);


Bagi saya ini berguna karena saya mencoba mengakses tampilan saudara di dalam onCreateView sebuah fragmen, di mana fragmen tersebut dideklarasikan dalam xml. Tampilan saudara masih nol di onCreateView karena induknya belum selesai menggembungkan, tetapi di onStart mereka punya :)
Daniel Wilson

3

Cobalah untuk menggeser tampilan pengaksesan Anda ke metode onViewCreated dari fragmen karena terkadang saat Anda mencoba mengakses tampilan dalam metode onCreate, tampilan tersebut tidak dirender pada saat menghasilkan pengecualian pointer nol.

 @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

Setuju, ini adalah kesalahan umum karena orang sering tidak benar-benar memahami cara kerja Fragmen saat mereka mulai mengerjakan pengembangan Android. Untuk mengurangi kebingungan, saya membuat kode contoh sederhana yang awalnya saya posting di Aplikasi dihentikan di emulator android , tetapi saya mempostingnya di sini juga.

Contohnya adalah sebagai berikut:

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>

Dan itu harus menjadi contoh yang valid, ini menunjukkan bagaimana Anda bisa menggunakan Aktivitas untuk menampilkan Fragmen, dan menangani kejadian di Fragmen itu. Dan juga bagaimana berkomunikasi dengan Activity yang ada di dalamnya.


1
Contoh ini menggunakan library android-support-v4 untuk FragmentActivity dan support fragment manager.
EpicPandaForce

1
contoh yang lebih lengkap tersedia di stackoverflow.com/questions/24840509/…
EpicPandaForce

1
Meskipun Anda harus menggunakan Ottountuk komunikasi, bukan callback, dan gunakan Butterknifeuntuk memasukkan tampilan.
EpicPandaForce

2

Tampilan "sesuatu" ada dalam fragmen dan bukan dalam aktivitas, jadi alih-alih mengaksesnya dalam aktivitas, Anda harus mengaksesnya di kelas fragmen seperti

Di 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

Anda mencoba mengakses elemen UI di onCreate()tetapi, terlalu dini untuk mengaksesnya, karena dalam tampilan fragmen dapat dibuat dalam onCreateView()metode. Dan onActivityCreated()metode ini dapat diandalkan untuk menangani tindakan apa pun padanya, karena aktivitas dimuat penuh dalam status ini.


1

Tambahkan yang berikut ini di activity_main.xml Anda

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

0

Karena Anda telah mendeklarasikan View Anda di fragment_main.xml, pindahkan potongan kode tersebut di mana Anda mendapatkan NPE dalam onCreateView()metode fragmen. Ini harus menyelesaikan masalah.


0

dalam kode yang diposting di atas pada pertanyaan ada masalah: Anda menggunakan R.layout.activity_main dalam metode oncreate, tetapi nama file xml adalah "fragment_main.xml", berarti Anda mencoba untuk mendapatkan tampilan file fragment_main.xml yang tidak ditampilkan sehingga memberikan pengecualian pointer nol. ubah kodenya seperti:

@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

Anda harus ingat hal penting adalah: NullPointerException terjadi ketika Anda telah mendeklarasikan variabel Anda dan mencoba mengambil nilainya sebelum memberikan nilai padanya.


0

Gunakan Metode onViewCreated () setiap kali menggunakan atau memanggil tampilan dari fragmen.

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

0

Saya mendapat NullPointerExceptioninisialisasi pendengar yang sama setelah memanggil findViewById() onCreate()dan onCreateView()metode.

Tapi ketika saya menggunakannya, onActivityCreated(Bundle savedInstanceState) {...}itu berhasil. Jadi, saya bisa mengakses GroupViewdan mengatur pendengar saya.

Semoga bermanfaat.


0

Perpustakaan paling populer untuk menemukan tampilan yang digunakan oleh hampir setiap pengembang.

Pisau mentega

Yang saya bisa adalah jawaban mereka yang cukup menjelaskan menemukan pandangan dengan metodologi yang tepat. Tetapi jika Anda adalah pengembang Android dan sering membuat kode setiap hari, maka Anda dapat menggunakan pisau mentega yang menghemat banyak waktu dalam menemukan tampilan dan Anda tidak perlu menulis kode untuk itu, Dengan dalam 2-3 langkah Anda dapat menemukan tampilan dalam milidetik .

Tambahkan ketergantungan di tingkat aplikasi gradle:

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

Tambahkan plugin untuk pisau mentega:

File -> Settings -> plugins-> 

Kemudian cari Android ButterKnife Zelezny dan instal plugin dan mulai ulang studio Anda dan selesai.

Sekarang masuk saja ke metode Oncreate aktivitas Anda dan klik kanan pada layout_name Anda dan ketuk tombol generate dan pilih opsi injeksi butterknife dan referensi tampilan Anda akan secara otomatis dibuat seperti yang disebutkan di bawah ini:

    @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;
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.