findViewByID null değerini döndürür


252

Her şeyden önce: evet, bu konudaki diğer tüm konuları okudum. Ve sadece bu siteden olanlar ... (görüyorsun, biraz sinirliyim)

Çoğu android:idsadece idXML dosyasında kullanmak için tavsiye ile geliyor . Yaptım.

Diğerlerinden öğrendim, bu View.findViewByIddurumdan farklı çalışıyor Activity.findViewById. Ben de hallettim.

Benim location_layout.xml, kullanıyorum:

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

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

Faaliyetlerimde:

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

ve özel görünüm sınıfımda:

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

geri döner null. Bunu yaptığımda, Etkinliğim iyi çalışıyor. Bu yüzden belki de çünkü var Activity.findViewByIdve View.findViewByIdfarklılıkların. Bu yüzden yerel olarak gümrük görünümü yapıcısına aktarılan içeriği sakladım ve denedim:

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

geri döndü null.

Sonra, ben genişletmek için benim özel görünüm değişti ViewGroupyerine Viewve değiştirilemez location_layout.xmlizin TextViewböylece, benim özel bir görünüm doğrudan çocuk olmak View.findViewByIdgerekiyordu olarak çalışması gerekir. Sürpriz: hiçbir şey çözmedi.

Peki ne yanlış yapıyorum?

Yorumlarınız için teşekkür ederim.


6
Proje de bozulursa, bu oluşabilir. Projeyi temizleyerek düzelttim
Pacerier

1
yanlış bağlam görünümü geçti
izzy

1
@ Pacerer teşekkür ederim. bu benim sorunumu çözdü. Xamarin'de android programlamadan nefret etmeye başlıyorum)
Artiom

@Pacerier "Temiz proje" de sorunumu çözdü. Dropbox projeyi bozdu.
Kohki Mametani

Yanıtlar:


271

boş döndürür

Muhtemelen çok erken aradığınız için. Kadar bekleyin onFinishInflate(). İçeriğine erişen bir geleneği gösteren örnek bir projeView .


67
AMAN TANRIM! O kadar önemsiz bir şey üzerinde gün geçirmek inanamıyorum. Ben setContentView () findViewById () çağrısının üzerine taşındı ve bu hile yaptı. Teşekkürler!
agentcurry

2
@CommonsWe doğru projeyi düşündünüz mü? Ginub.com/commonsguy/cw-advandroid/tree/master/Animation/… 'de hiçbir yerde onFinishInflate görmüyorum
likejudo

1
@likejiujitsu: Bunu 2010'da geri almış olabilir. Daha yeni bir projenin bağlantısını güncelledim onFinishInflate().
CommonsWare

3
Daha önce findViewById çağırdı benim setContentView var ve hala boş. EditText'e atıfta bulunuyorum
Neon Warge

1
Her zaman sabit GitHub işlemlerine bağlantı verin (örn. Github.com/commonsguy/cw-omnibus/tree/… ) ve asla depoları veya
rebase'i silmeyin

145

Muhtemelen, aramadan findViewByIdönce setContentViewmi arıyorsunuz? Bu durumda, arama findViewById SONRASI aramayı deneyinsetContentView


1
Böyle kolay bir hata yapmak ama ne yazık ki bu yapmıştım. Hata ayıklayıcı işe yaramaz çünkü hatanın yeni niyet satırımda aradığım gerçek yeni etkinlikte olmadığını söyledi. Teşekkürler!
edude05

6
Aslında yanlış görünüme işaret eden setContentView çağırıyor çünkü bu hatayı vardı ... ne yazık ki derleyici bu tür hata yakalamıyor.
HeatfanJohn

Evet, setContentView'ı yanlışlıkla sildim ve programımın neden ezilmeye başladığını anlamadım.
Ronen Festinger

100

Farklı ekran yoğunlukları için mizanpajınızın birden fazla sürümüne sahip olmadığınızdan emin olun. Varolan bir düzene yeni bir kimlik eklerken bir kez bu soruna rastladım ancak hdpi sürümünü güncellemeyi unuttum. Düzen dosyasının tüm sürümlerini güncellemeyi unutursanız, bazı ekran yoğunlukları için çalışır, ancak diğerleri için çalışmaz.


8
TEŞEKKÜRLER! Öyleydi. (Benim durumumda farklı Android sürümü için birden fazla sürümüm var). Her düzen dosyasının üstüne ve altına devasa bir yorum yazmama rağmen her zaman unutuyorum. Bu durumda derleyici bir hata veya büyük uyarı yapsaydı.
tiktak

Ding ding ding, çok teşekkür ederim!
Zach

21

Özel bir görünümde yanlış süper yapıcı çağırırsanız FindViewById boş olabilir. Kimlik etiketi, attr'lerin bir parçasıdır, bu nedenle attr'leri yoksayarsanız, kimliği silmiş olursunuz.

Bu yanlış olur

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

Doğru

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

1
Çok teşekkür ederim efendim! Dikkatsizim, IDE ile ilgili bir sorun olduğundan şüphe bile ettim. Cevabınız için ne kadar şanslısınız.
EffectiveMatrix

Özel görünümümü oluştururken bu hatayı yaptım. Teşekkürler repkap11.
Andrew

15

Benim durumumda, projemde 2 etkinlik vardı main.xmlve main2.xml. Başından beri main2bir kopyası olduğunu mainve yeni eklenen kadar herşey iyi çalıştı TextViewetmek main2, böylece R.id.textview1uygulamanın geri kalanı için kullanılabilir hale geldi. Sonra standart arayarak getirmeye çalıştı:

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

ve her zaman boştu. onCreateYapıcıda ben değil main2, diğerinin somutlaştığı ortaya çıktı . Sahiptim:

setContentView(R.layout.main);

onun yerine

setContentView(R.layout.main2);

Ben buraya, sitede geldi sonra bunu fark ettim.


14

Başka yerlerde bahsedilen klasik nedenlerin yanı sıra:

  • Emin aradım olun setContentView()öncefindViewById()
  • idİstediğiniz öğenin verdiğiniz görünümde veya düzende olduğundan emin olunsetContentView()
  • idFarklı düzenlerde yanlışlıkla kopyalanmadığından emin olun

Standart mizanpajlarda, dokümantasyona aykırı olan özel görünümler için bulduğum bir tane var:

Teorik olarak, özel bir görünüm oluşturabilir ve bunu bir mizanpaja ekleyebilirsiniz ( buraya bakın ). Ancak, bu gibi durumlarda, bazen idözelliğin dışındaki düzende tüm görünümler için özniteliğin çalıştığını buldum . Kullandığım çözüm:

  1. Her özel görünümü, özel görünümde FrameLayoutolmasını istediğiniz düzen özelliklerine sahip bir ile değiştirin . Uygun bir ver iddiyelim frame_for_custom_view.
  2. İçinde onCreate:

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

    özel görünümü çerçeveye yerleştirir.


Bu bana yardımcı oldu: "İstediğiniz kimliğin setContentView () öğesine verdiğiniz görünümde veya mizanpajda olduğundan emin olun". Ancak bir alt görünüm olduğunda ne yapmalı? Üst görünümü almayı denedikten sonra parentView.findById () yapın, ancak yine de null döndürüyor
NaturalBornCamper

@naturalborncamper Eğer örnek kod ile ayrı bir soru gönderirseniz bir göz atacağım.
Neil Townsend

Teşekkürler Neil, ben zaten yayınladım ve birileri bunu yapmanın daha iyi bir yolunu gösterdi, ancak tam olarak nasıl olması gerektiği konusunda çalışmıyor, bu yüzden farklı bir strateji kullanmak zorunda kaldım: stackoverflow.com/questions/47955376/…
NaturalBornCamper

9
    @Override
protected void onStart() {
         // use findViewById() here instead of in onCreate()
    }

6

ExpandableListView kullananlar ve bu soruya başlıklarına göre girenler için bir cevap.

Bir ExpandableListView uygulamasının bir parçası olarak çocuğum ve grup görünümlerinde TextViews ile çalışırken bu hatayla karşılaştım.

GetChildView () ve getGroupView () yöntemleri uygulamalarınızda aşağıdakine benzer bir şey kullanabilirsiniz.

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

Bunu burada buldum .


5

Android / Eclipse için oldukça yeniyim, yanlışlıkla activity_main.xmlyerine UI şeyler ekledim fragment_main.xml. Bunu çözmem için birkaç saatim oldu ...


5

FWIW, kimsenin bunu ihtiyacım olanla aynı şekilde çözdüğünü görmüyorum. Derleme zamanında hiçbir şikayet, ama çalışma zamanında boş bir görünüm alıyordu ve uygun sırayla şeyler çağırıyordu. Yani, setContentView () öğesinden sonra findViewById (). Sorun, görünümümün content_main.xml içinde tanımlandığı ortaya çıktı, ancak etkinlik_main.xml dosyamda şu ifadeden yoksunum:

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

Bunu activity_main.xml dosyasına eklediğimde, artık NullPointer yok.


Bir Parçayı kopyalayıp yapıştırmadaki sorun, bazen bazı şeyleri değiştirmeyi unutmanızdır ... bunlardan birini şişirmek için doğru düzen olmaktır. Teşekkürler!
Pablo Quemé

3

Aynı sorunu yaşadım. Bir GridView için bağdaştırıcılarını geçersiz kılmanıza ve her GridView hücresi için kendi düzeninizi belirtmenize izin veren bir üçüncü taraf kitaplığı kullanıyordum.

Sonunda ne olduğunu anladım. Eclipse, GridView içindeki her hücre için kütüphanenin yerleşim xml dosyasını kullanıyordu, bununla ilgili hiçbir bilgi vermese de. Özel bağdaştırıcımda, çalışma zamanında olsa da kendi projemdeki xml kaynağını kullandığını belirtti.

Yaptığım şey, özel xml düzenlerimin ve kimliklerimin hala kütüphanede oturanlardan farklı olduğundan emin olmaktı, projeyi temizledi ve sonra projemdeki doğru özel düzenleri okumaya başladı.

Kısacası, bir üçüncü taraf kütüphanesinin adaptörünü geçersiz kılar ve adaptörün kullanması için kendi düzen xml'nizi belirtirseniz dikkatli olun. Projenizdeki düzeniniz kitaplıktakiyle aynı dosya adına sahipse, bulunması gerçekten zor bir hatayla karşılaşabilirsiniz!


3

Benim özel durumumda, bir ListView altbilgi eklemek çalışıyordu. OnCreate () içindeki aşağıdaki çağrı null döndürüyordu.

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

Kimlikle bulmak yerine altbilgi görünümünü şişirmek için bunu değiştirmek bu sorunu çözdü.

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

2

Benim durumumda, ExpandableListView kullanıyordum ve ayarlamıştım android:transcriptMode="normal". Bu, genişletilebilir gruptaki birkaç çocuğun kaybolmasına neden oluyordu ve listeyi kaydırdığımda NULL istisnası alıyordum.


2

Benim için aynı aktivite için iki xml düzenim vardı - biri portre modunda, diğeri manzara modunda. Tabii ki manzara xml bir nesnenin kimliğini değiştirmişti ama aynı sürüm portre sürümünde yapmayı unutmuştu. Birini değiştirdiğinizde diğer xml ile aynı yaptığınızdan emin olun veya siz çalıştırıp hata ayıklamanıza ve bir değişiklik yapmadığınız kimliği bulana kadar bir hata almayacaksınız. Aptal hatalar, neden beni cezalandırmalısın?


2

Etkinlik içeriğini bir düzen kaynağından ayarlayın. yani., setContentView(R.layout.basicXml);


2

Yukarıdaki çözümlere ek olarak,
tools:context=".TakeMultipleImages" mizanpajda mainfest.xml dosyasında aynı değer olursunuz:
android:name=".TakeMultipleImages" aynı etkinlik öğesi için. yeni etkinlik oluşturmak için kopyala ve yapıştır kullanıldığında meydana gelir


2

Aynı problemim var, ama bence sizinle paylaşmaya değer. ViewById öğesini özel düzende bulmanız gerekiyorsa, örneğin:

public class MiniPlayerControllBar extends LinearLayout {
    //code
}

görünümü yapıcıda alamazsınız. Görünüm şiştikten sonra findViewById öğesini çağırmalısınız. Onları geçersiz kılabileceğiniz bir yöntemdironFinishInflate


2

Sadece özel durumumu buraya atmak istedim. Hatta birisine yardım edebilir.

Ben bu gibi Android UI XML direktifini kullanıyordum:

Ana görünüm:

<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" />

Çocuk görünümü (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) her zaman null değerini döndürür. Ancak, kimliği alt görünümden include etiketine taşıdıysam çalışmaya başladı.

Sabit ebeveyn:

<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" />

Sabit çocuk:

<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">

2

Benim durumum yukarıdaki gibi değil, hiçbir çözüm işe yaramadı. Görüşümün, düzen hiyerarşisinde çok derin olduğunu varsayıyorum. Ben bir seviye yukarı taşındı ve artık boş değildi.


Ben de aynı sorun var, bir seviye daha yüksek de bulunabilir .. bu oldukça sinir bozucu ve ben istediğim gibi benim menü yapamam gibi neden olduğunu bilmek istiyorum
NaturalBornCamper

Derin düzen hiyerarşileri anti-desen, neredeyse her zaman daha temiz bir çözüm var. Araç çubuğundaki taşma menüsü veya gezinme çekmecesinden mi bahsediyorsunuz?
Deividas Strioga

Gezinme çekmecesi, bir gruba bir menü öğesi eklemenin işe yaramaması dışında, aslında başka bir soru yayınladım, sadece tüm öğelerin sonuna ekler: stackoverflow.com/questions/47955376/…
NaturalBornCamper

1

Benim durumumda düzeni şişirmişti ama çocuk görüşleri boş dönüyordu. Başlangıçta bu vardı:

@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);
    ...
}

Ancak, bunu aşağıdaki şekilde değiştirdiğimde işe yaradı:

@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);
    ...
}

Anahtar, çocuk görüşlerini almak için zaten şişirilmiş düzene referans vermekti. Yani, eklemek için footerView:

  • footerView .findViewById ...

0

Deneyimlerime göre, bu durum kodunuz OnDestroyView'dan sonra çağrıldığında da olabilir (parça arka yığın üzerindeyken). Bir BroadCastReceiver'ın girişindeki kullanıcı arayüzünü güncelliyorsanız, durumun bu olup olmadığını kontrol etmeniz gerekir .


0

DÜZENİ İNFLATE !! (kimliği içerir)

Benim durumumda findViewById () öğesi, öğenin yazıldığı düzen şişirilmediğinden null döndürdü ...

Örneğin. fragment_layout.xml

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

findViewById (R.id.listview) null döndürdü, çünkü inflater.inflate (R.layout.fragment_layout, ..., ...); ondan önce.

Umarım bu cevap hepinize yardımcı olur.



0

findViewById ayrıca bir Fragment içindeyseniz null değerini döndürebilir. Burada açıklandığı gibi: fragmanda findViewById

Bir Parça içindeki en üst düzey Görünümü döndürmek için getView () öğesini çağırmalısınız. Ardından düzen öğelerini (düğmeler, metin görünümleri, vb.) Bulabilirsiniz.


0

Ben yukarıdaki hiçbir şey çalıştı çalıştım .. bu yüzden benim ImageView statik yapmak zorunda kaldı public static ImageView texture;ve sonra texture = (ImageView) findViewById(R.id.texture_back);, olsa iyi bir yaklaşım olduğunu sanmıyorum ama bu gerçekten benim durumum için çalıştı :)


üzgünüm, statik görünüm kötü bir fikir olduğunu düşünüyorum
vuhung3990

0

Benim durumumda, çağrıyı üst nesneden üst öğe tarafından başlatılan bir bağdaştırıcı nesnesine taşıdığımda findViewById null değerini döndürdü. Burada listelenen hileleri başarılı olmadan denedikten sonra, findViewById öğesini üst nesneye geri taşıdım ve sonucu adaptör nesnesinin somutlaştırılması sırasında parametre olarak geçtim. Örneğin, bunu üst nesnede yaptım:

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

Daha sonra adaptör nesnesinin oluşturulması sırasında hdSpinner'ı parametre olarak geçtim:

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

0

Etkinlik kimliğimdeki alanlardan biri başka bir etkinlikteki kimlikle eşleştiği için benim için kilitlendi. Benzersiz bir kimlik vererek düzelttim.

LoginActivity.xml şifremde alan kimliği "şifre" idi. Kayıt etkinliğimde sadece id r_password vererek sabitledim, sonra null nesnesi döndürmedi:

password = (EditText)findViewById(R.id.r_password);

0

A için özel bir görünüm yapmaya çalışırken benzer bir sorunla karşı karşıya kaldım ListView.

Bunu basitçe yaparak çözdüm:

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);

0

Hata ayıklama ve sorunu bulma yolları:

  • Etkinliğinizdeki tüm findViewById öğelerini yorumlayın.
  • OnCreate ve setContentView dışındaki her şeyi yorumlayın
  • Projeyi çalıştırın ve herhangi bir düzen ayarlanıp ayarlanmadığına bakın

Benim durumumda, hem uygulama modülümde hem de kütüphane modülümde activity_main.xml kullanıyordum. Dolayısıyla, yukarıdaki adımları gerçekleştirdiğimde, kütüphanede tasarladığım düzen yerine, uygulama modülünün içindeki düzen şişirildi.

Bu yüzden activity_main.xml dosya adını activity_main_lib.xml olarak değiştirdim.

Bu nedenle , projenizin tamamında yinelenen düzen adlarının olmadığından emin olun .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.