findViewByID mengembalikan nol

252

Pertama-tama: ya, saya membaca semua utas lainnya tentang topik ini. Dan bukan hanya mereka yang berasal dari situs ini ... (Anda lihat, saya sedikit frustrasi)

Sebagian besar dari mereka datang dengan saran untuk digunakan, android:idbukan hanya iddalam file XML. Aku melakukannya.

Dari yang lain, saya belajar, itu View.findViewByIdbekerja berbeda dari Activity.findViewById. Saya menanganinya juga.

Di saya location_layout.xml, saya menggunakan:

<FrameLayout .... >
    <some.package.MyCustomView ... />

    <LinearLayout ... >
        <TextView ...
            android:id="@+id/txtLat" />
        ...
    </LinearLayout>
</FrameLayout>

Dalam Aktivitas saya, saya lakukan:

...
setContentView( R.layout.location_layout );

dan di kelas tampilan khusus saya:

... 
TextView tv = (TextView) findViewById( R.id.txtLat );

yang kembali null. Melakukan ini, Aktivitas saya berfungsi dengan baik. Jadi mungkin itu karena Activity.findViewByIddan View.findViewByIdperbedaan. Jadi saya menyimpan konteks yang diteruskan ke konstruktor tampilan pabean secara lokal dan mencoba:

...
TextView tv = (TextView) ((Activity) context).findViewById( R.id.txtLat );

yang juga dikembalikan null.

Kemudian, saya mengubah tampilan kustom saya untuk memperpanjang ViewGroupbukan Viewdan mengubah location_layout.xmluntuk membiarkan TextViewmenjadi anak langsung dari tampilan kustom saya, sehingga View.findViewByIdharus bekerja sebagai seharusnya. Mengejutkan: itu tidak menyelesaikan apa pun.

Jadi apa yang saya lakukan salah?

Saya akan menghargai komentar Anda.

Thomas
sumber
6
Ini dapat terjadi jika proyek rusak juga. Saya memperbaikinya dengan membersihkan proyek
Pacerier
1
melewati tampilan konteks yang salah terima kasih
izzy
1
@Pacerier terima kasih. yang memecahkan masalah saya. Saya mulai membenci pemrograman android di Xamarin)
Artiom
@Pacerier "Proyek bersih" juga menyelesaikan masalah saya. Tampaknya Dropbox merusak proyek.
Kohki Mametani

Jawaban:

271

yang mengembalikan nol

Mungkin karena Anda memanggilnya terlalu dini. Tunggu sampai onFinishInflate(). Berikut adalah contoh proyek yang menunjukkan suatu kebiasaan Viewmengakses kontennya.

CommonsWare
sumber
67
OH TUHAN! Aku tak percaya aku menghabiskan hari untuk sesuatu yang sepele. Saya memindahkan setContentView () di atas panggilan findViewById () dan itu berhasil. Terima kasih!
agentcurry
2
@ UmumApakah itu proyek yang benar? Saya tidak melihat onFinishInflate di mana saja di github.com/commonsguy/cw-advandroid/tree/master/Animation/…
likejudo
1
@likejiujitsu: Mungkin sudah kembali pada tahun 2010. Saya telah memperbarui tautan ke proyek yang lebih baru onFinishInflate().
CommonsWare
3
Saya meminta setContentView saya dipanggil sebelum findViewById dan itu masih nol. Saya mereferensikan EditText
Neon Warge
1
Selalu taut ke komit GitHub yang diperbaiki (mis. Github.com/commonsguy/cw-omnibus/tree/… ) dan jangan pernah menghapus repo atau rebase ;-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
145

Mungkin, Anda menelepon findViewByIdsebelum menelepon setContentView? Jika demikian, coba panggil findViewById SETELAH panggilansetContentView

Bayram Boyraz
sumber
1
Kesalahan yang mudah dilakukan, tetapi sayangnya inilah yang telah saya lakukan. Debugger tidak ada gunanya karena katanya kesalahan itu pada garis maksud baru saya tidak dalam aktivitas baru yang sebenarnya saya panggil. Terima kasih!
edude05
6
Sebenarnya saya mengalami kesalahan ini karena saya memanggil setContentView menunjuk ke tampilan yang salah ... sayangnya kompiler tidak menangkap kesalahan jenis ini.
HeatfanJohn
Ya, saya telah menghapus setContentView secara tidak sengaja dan tidak mengerti mengapa program saya mulai rusak.
Ronen Festinger
100

Pastikan Anda tidak memiliki beberapa versi tata letak untuk kepadatan layar yang berbeda. Saya mengalami masalah ini sekali ketika menambahkan id baru ke tata letak yang ada tetapi lupa untuk memperbarui versi hdpi. Jika Anda lupa memperbarui semua versi file tata letak itu akan berfungsi untuk beberapa kepadatan layar tetapi tidak yang lain.

Joe
sumber
8
TERIMA KASIH! Itu dia. (Dalam kasus saya, saya memiliki beberapa versi untuk versi Android yang berbeda). Saya lupa tentang hal itu sepanjang waktu meskipun saya menaruh komentar raksasa di atas dan bawah setiap file tata letak. Saya berharap kompiler akan membuat kesalahan atau peringatan besar jika ini terjadi.
tiktak
Ding ding ding, terima kasih banyak! Membungkukkan otakku di atas lol ini
Zach
21

FindViewById bisa menjadi nol jika Anda memanggil konstruktor super yang salah dalam tampilan kustom. Tag ID adalah bagian dari attrs, jadi jika Anda mengabaikan attrs, Anda menghapus ID.

Ini salah

public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context);
}

Ini benar

public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context,attrs);
}
repkap11
sumber
1
Terima kasih banyak, tuan! Begitu ceroboh saya, saya bahkan meragukan ada sesuatu yang salah dengan IDE saya. Betapa beruntungnya memenuhi jawaban Anda.
EffectiveMatrix
Saya membuat kesalahan ini ketika saya membuat tampilan kustom saya. Terima kasih, repkap11.
Andrew F.
15

Dalam kasus saya, saya punya 2 kegiatan di proyek saya, main.xmldan main2.xml. Dari awal, main2adalah salinan main, dan semuanya bekerja dengan baik, sampai aku tambah baru TextViewuntuk main2, sehingga R.id.textview1menjadi tersedia untuk sisa aplikasi. Kemudian saya mencoba mengambilnya dengan panggilan standar:

TextView tv = (TextView) findViewById( R.id.textview1 );

dan itu selalu nol. Ternyata, bahwa dalam onCreatekonstruktor saya instantiating bukan main2, tetapi yang lain. Saya punya:

setContentView(R.layout.main);

dari pada

setContentView(R.layout.main2);

Saya perhatikan ini setelah saya tiba di sini, di situs.

infografnet
sumber
14

Di samping penyebab klasik, disebutkan di tempat lain:

  • Pastikan Anda sudah menelepon setContentView()sebelumnyafindViewById()
  • Pastikan bahwa yang idAnda inginkan ada di tampilan atau tata letak yang Anda berikansetContentView()
  • Pastikan bahwa idtidak secara tidak sengaja diduplikasi dalam tata letak yang berbeda

Ada satu yang saya temukan untuk tampilan khusus dalam tata letak standar, yang bertentangan dengan dokumentasi:

Secara teori Anda dapat membuat tampilan khusus dan menambahkannya ke tata letak ( lihat di sini ). Namun, saya telah menemukan bahwa dalam situasi seperti itu, terkadang idatribut berfungsi untuk semua tampilan di tata letak kecuali yang kustom. Solusi yang saya gunakan adalah:

  1. Ganti setiap tampilan kustom dengan FrameLayoutproperti tata letak yang sama seperti yang Anda inginkan untuk tampilan kustom. Berikan yang sesuai id, katakanlahframe_for_custom_view .
  2. Dalam onCreate:

    setContentView(R.layout.my_layout);
    FrameView fv = findViewById(R.id.frame_for_custom_layout);
    MyCustomView cv = new MyCustomView(context);
    fv.addView(cv);

    yang menempatkan tampilan khusus dalam bingkai.

Neil Townsend
sumber
Ini membantu saya: "Pastikan id yang Anda inginkan ada di tampilan atau tata letak yang Anda berikan ke setContentView ()". Apa yang harus dilakukan ketika itu adalah subview? Sudah mencoba mendapatkan tampilan induk kemudian lakukan parentView.findById () tetapi masih mengembalikan nol
NaturalBornCamper
@naturalborncamper jika Anda memposting pertanyaan terpisah dengan kode contoh saya akan melihatnya.
Neil Townsend
Terima kasih Neil, saya sudah memposting dan seseorang menunjuk cara yang lebih baik untuk melakukan ini, meskipun itu tidak bekerja persis bagaimana seharusnya jadi saya harus menggunakan strategi yang berbeda: stackoverflow.com/questions/47955376/…
NaturalBornCamper
9
    @Override
protected void onStart() {
         // use findViewById() here instead of in onCreate()
    }
Jonathan
sumber
6

Sebuah jawaban untuk mereka yang menggunakan ExpandableListView dan mengalami pertanyaan ini berdasarkan judulnya.

Saya mengalami kesalahan ini ketika mencoba untuk bekerja dengan TextViews di tampilan anak dan grup saya sebagai bagian dari implementasi ExpandableListView.

Anda dapat menggunakan sesuatu seperti yang berikut ini dalam implementasi Anda dari metode getChildView () dan getGroupView ().

        if (convertView == null) {
            LayoutInflater inflater =  (LayoutInflater) myContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.child_layout, null);
        }

Saya menemukan ini di sini .

Josh Metcalfe
sumber
5

Saya cukup baru di Android / Eclipse, karena kesalahan saya menambahkan hal-hal UI untuk activity_main.xmlbukan fragment_main.xml. Butuh waktu beberapa jam untuk mencari tahu ...

lama12345
sumber
5

FWIW, saya tidak melihat ada yang menyelesaikan ini dengan cara yang persis sama seperti yang saya butuhkan. Tidak ada keluhan pada waktu kompilasi, tapi saya mendapatkan tampilan nol saat runtime, dan memanggil berbagai hal dengan urutan yang benar. Yaitu, findViewById () setelah setContentView (). Masalahnya ternyata tampilan saya didefinisikan dalam content_main.xml, tetapi di activity_main.xml saya, saya tidak memiliki pernyataan yang satu ini:

<include layout="@layout/content_main" />

Ketika saya menambahkan itu ke activity_main.xml, tidak ada lagi NullPointer.

ferris
sumber
Masalah dengan menyalin paste Fragmen adalah bahwa Anda lupa untuk mengubah beberapa hal kadang-kadang ... menjadi tata letak yang benar untuk mengembang salah satunya. Terima kasih!
Pablo Quemé
3

Saya punya masalah yang sama. Saya menggunakan pustaka pihak ketiga yang memungkinkan Anda mengganti adaptor mereka untuk GridView dan menentukan tata letak Anda sendiri untuk setiap sel GridView.

Saya akhirnya menyadari apa yang terjadi. Eclipse masih menggunakan file xml tata letak perpustakaan untuk setiap sel di GridView, meskipun itu tidak menunjukkan hal ini. Dalam adaptor khusus saya, itu menunjukkan bahwa ia menggunakan sumber daya xml dari proyek saya sendiri meskipun saat runtime, itu tidak.

Jadi yang saya lakukan adalah memastikan layout dan id xml kustom saya berbeda dari yang masih ada di perpustakaan, membersihkan proyek dan kemudian mulai membaca tata letak kustom yang benar yang ada di proyek saya.

Singkatnya, berhati-hatilah jika Anda mengganti adaptor perpustakaan pihak ketiga dan menentukan tata letak Anda sendiri xml agar adaptor dapat digunakan. Jika tata letak Anda di dalam proyek Anda memiliki nama file yang sama dengan yang ada di perpustakaan, Anda mungkin menemukan bug yang sangat sulit ditemukan!

JDJ
sumber
3

Dalam kasus khusus saya, saya mencoba menambahkan footer ke ListView. Panggilan berikut di onCreate () kembali nol.

TextView footerView = (TextView) placesListView.findViewById(R.id.footer);

Mengubah ini untuk mengembang tampilan footer alih-alih menemukannya dengan ID menyelesaikan masalah ini.

View footerView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.footer_view, null, false);
Mat
sumber
2

Dalam kasus saya, saya menggunakan ExpandableListView dan telah saya atur android:transcriptMode="normal". Ini menyebabkan beberapa anak dalam grup yang dapat diperluas menghilang dan saya biasa mendapatkan pengecualian NULL ketika saya pernah menggunakan daftar gulir.

Astaga
sumber
2

Bagi saya, saya memiliki dua tata letak xml untuk aktivitas yang sama - satu dalam mode potret dan satu di lanskap. Tentu saja saya telah mengubah id dari suatu objek di landscape xml tetapi lupa untuk membuat perubahan yang sama dalam versi potret. Pastikan jika Anda mengubah yang Anda lakukan sama dengan xml lain atau Anda tidak akan mendapatkan kesalahan sampai Anda menjalankan / debug itu dan tidak dapat menemukan id Anda tidak berubah. Oh, kesalahan bodoh, mengapa Anda harus menghukum saya begitu?

ColossalChris
sumber
2

Setel konten aktivitas dari sumber daya tata letak. yaitu., setContentView(R.layout.basicXml);

Ajay Takur
sumber
2

Selain solusi di atas, Anda memastikan bahwa
tools:context=".TakeMultipleImages" dalam tata letak nilai yang sama di file mainfest.xml:
android:name=".TakeMultipleImages"untuk elemen aktivitas yang sama. itu terjadi ketika menggunakan salin dan tempel untuk membuat aktivitas baru

pengguna2982286
sumber
2

Saya memiliki masalah yang sama, tetapi saya pikir ini layak untuk dibagikan kepada kalian. Jika Anda harus menemukanViewById di tata letak khusus, misalnya:

public class MiniPlayerControllBar extends LinearLayout {
    //code
}

Anda tidak dapat memperoleh tampilan dalam konstruktor. Anda harus memanggil findViewById setelah tampilan meningkat. Mereka adalah metode yang dapat Anda gantionFinishInflate

Shaw
sumber
2

Hanya ingin melempar kasus khusus saya di sini. Mungkin bisa membantu seseorang di telepon.

Saya menggunakan arahan dalam Android UI XML saya seperti ini:

Tampilan induk:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="home_phone"
    android:background="@color/colorPrimary">

    ...

    <include
        layout="@layout/retry_button"
        android:visibility="gone" />

Tampilan anak (retry_button):

<com.foo.RetryButton
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/retry"
    android:layout_gravity="center"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="140dp">

.findViewById (R.id.retry) akan selalu mengembalikan nol. Tapi, jika saya memindahkan ID dari tampilan anak ke tag sertakan, itu mulai berfungsi.

Induk tetap:

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:tag="home_phone"
    android:background="@color/colorPrimary">

    ...

    <include
        layout="@layout/retry_button"
        android:id="@+id/retry"
        android:visibility="gone" />

Anak tetap:

<com.foo.RetryButton
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_gravity="center"
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="140dp">
John D.
sumber
2

Kasus saya tidak seperti di atas, tidak ada solusi yang berhasil. Saya menganggap pandangan saya terlalu jauh ke dalam hierarki tata letak. Saya memindahkannya satu tingkat ke atas dan bukan nol lagi.

Deividas Strioga
sumber
Saya memiliki masalah yang sama, satu tingkat lebih tinggi juga dapat ditemukan .. itu cukup menjengkelkan dan saya ingin tahu mengapa itu terjadi karena saya tidak dapat membuat menu seperti yang saya inginkan
NaturalBornCamper
Hirarki tata letak yang dalam adalah anti-pola, hampir selalu ada solusi yang lebih bersih. Apakah Anda berbicara tentang menu overflow di bilah alat, atau laci navigasi?
Deividas Strioga
Laci Navigasi, saya sebenarnya sudah mengirimkan pertanyaan lain, kecuali bahwa menambahkan item menu di dalam grup tidak berfungsi, cukup tambahkan di akhir semua item: stackoverflow.com/questions/47955376/…
NaturalBornCamper
1

Dalam kasus saya, saya telah meningkatkan tata letak tetapi pandangan anak kembali nol. Awalnya saya punya ini:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_history);

    footerView = ((LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.listview_footer, null, false);
    pbSpinner = (ProgressBar) findViewById(R.id.pbListviewFooter);
    tvText = (TextView) findViewById(R.id.tvListviewFooter);
    ...
}

Namun, ketika saya mengubahnya ke yang berikut ini berfungsi:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_history);

    footerView = ((LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.listview_footer, null, false);
    pbSpinner = (ProgressBar) footerView.findViewById(R.id.pbListviewFooter);
    tvText = (TextView) footerView.findViewById(R.id.tvListviewFooter);
    ...
}

Kuncinya adalah secara khusus referensi tata letak yang sudah meningkat untuk mendapatkan tampilan anak. Artinya, untuk menambahkan footerView:

  • footerView .findViewById ...
Suragch
sumber
0

Dalam pengalaman saya, sepertinya ini juga bisa terjadi ketika kode Anda dipanggil setelah OnDestroyView (ketika fragmen berada di tumpukan belakang). Jika Anda memperbarui UI pada input dari BroadCastReceiver, Anda harus memeriksa apakah ini masalahnya .

Tad
sumber
0

INFLATE LAYOUT !! (yang berisi id)

Dalam kasus saya findViewById () mengembalikan nol, karena tata letak di mana elemen ditulis, tidak meningkat ...

Misalnya. fragment_layout.xml

<ListView
android:id="@+id/listview">

findViewById (R.id.listview) mengembalikan nol, karena saya belum melakukan inflater.inflate (R.layout.fragment_layout, ..., ...); sebelum itu.

Semoga jawaban ini membantu Anda semua.

TABUT
sumber
0

Perbaikan saya adalah hanya membersihkan proyek.

Liangjun
sumber
0

findViewById juga dapat mengembalikan nol jika Anda berada di dalam Fragmen. Seperti dijelaskan di sini: findViewById di Fragment

Anda harus memanggil getView () untuk mengembalikan Tampilan tingkat atas di dalam Fragmen. Kemudian Anda dapat menemukan item tata letak (tombol, tampilan teks, dll)

teknokrat
sumber
0

Saya sudah mencoba semua hal di atas tidak berfungsi .. jadi saya harus membuat ImageView saya statispublic static ImageView texture; dan kemudian texture = (ImageView) findViewById(R.id.texture_back);, saya tidak berpikir itu pendekatan yang baik, tetapi ini benar-benar bekerja untuk kasus saya :)

Tabish
sumber
maaf, saya pikir tampilan statis adalah ide yang buruk
vuhung3990
0

Dalam kasus saya, findViewById mengembalikan nol ketika saya memindahkan panggilan dari objek induk ke objek adaptor yang dipakai oleh induk. Setelah mencoba trik yang tercantum di sini tanpa hasil, saya memindahkan findViewById kembali ke objek induk dan meneruskan hasilnya sebagai parameter selama instantiation objek adaptor. Misalnya, saya melakukan ini di objek induk:

 Spinner hdSpinner = (Spinner)view.findViewById(R.id.accountsSpinner);

Lalu saya melewati hdSpinner sebagai parameter selama pembuatan objek adaptor:

  mTransactionAdapter = new TransactionAdapter(getActivity(),
        R.layout.transactions_list_item, null, from, to, 0, hdSpinner);
Lexo
sumber
0

Itu macet untuk saya karena salah satu bidang di id aktivitas saya cocok dengan id di aktivitas lain. Saya memperbaikinya dengan memberikan id unik.

Dalam id bidang kata sandi loginActivity.xml saya adalah "kata sandi". Dalam aktivitas registrasi saya, saya hanya memperbaikinya dengan memberikan id r_password, lalu mengembalikannya bukan objek nol:

password = (EditText)findViewById(R.id.r_password);
Jageloo Yadav
sumber
0

Saya menghadapi masalah yang sama ketika saya mencoba melakukan tampilan kustom untuk ListView .

Saya menyelesaikannya hanya dengan melakukan ini:

public View getView(int i, View view, ViewGroup viewGroup) {

    // Gets the inflater
    LayoutInflater inflater = LayoutInflater.from(this.contexto);

    // Inflates the layout
    ConstraintLayout cl2 = (ConstraintLayout) 
    inflater.inflate(R.layout.custom_list_view, viewGroup, false);

    //Insted of calling just findViewById, I call de cl2.findViewById method. cl2 is the layout I have just inflated. 
     TextView tv1 = (TextView)cl2.findViewById(cl2);
Rafael Costa
sumber
0

Cara melakukan debug dan menemukan masalah:

  • Komentari semua findViewById dalam aktivitas Anda.
  • Mengomentari semuanya kecuali onCreate dan setContentView
  • Jalankan proyek dan lihat apakah ada tata letak yang ditetapkan

Dalam kasus saya, saya menggunakan activity_main.xml di modul aplikasi saya dan juga modul perpustakaan saya. Jadi ketika saya melakukan langkah-langkah di atas, alih-alih tata letak yang saya rancang di perpustakaan, tata letak di dalam modul aplikasi meningkat.

Jadi saya mengubah nama file activity_main.xml menjadi activity_main_lib.xml.

Jadi pastikan Anda tidak memiliki nama tata letak duplikat di seluruh proyek Anda .

Reejesh PK
sumber