findViewById (), diğer bileşenler için değil, düzen XML'deki özel bileşen için null döndürür


93

res/layout/main.xmlBu unsurları ve diğerlerini içeren bir içeriğim var:

<some.package.MyCustomView android:id="@+id/foo" (some other params) />
<TextView android:id="@+id/boring" (some other params) />

Etkinliğim onCreate'de şunu yapıyorum:

setContentView(R.layout.main);
TextView boring = (TextView) findViewById(R.id.boring);
// ...find other elements...
MyCustomView foo = (MyCustomView) findViewById(R.id.foo);
if (foo == null) { Log.d(TAG, "epic fail"); }

Diğer öğeler başarıyla bulundu, ancak fooboş olarak geri dönüyor. MyCustomView bir kurucuya sahiptir MyCustomView(Context c, AttributeSet a)ve bu kurucunun Log.d(...)sonunda bir "epic fail" den hemen önce logcat'te başarıyla görünür.

Neden fooboş?

Yanıtlar:


184

Çünkü kurucuda, super(context)onun yerine vardı super(context, attrs).

İd gibi öznitelikleri aktarmazsanız, bu durumda görünümün kimliği olmayacak ve bu nedenle bu id kullanılarak bulunamayacaktır. :-)


1
Kendi sorularınızı yanıtlayabilmek her zaman güzel :) Sizinkini de kabul edilen yanıt olarak işaretlediğinizden emin olun.
MattC

Aslında. SO bana izin verdiğinde bunu yapacak ("2 gün içinde kendi cevabınızı kabul edebilirsiniz.")
Chris Boyle

4
Ayrıca, çizgiler sever olmamalıdır (MyCustomView) foo = findViewById(R.id.foo);olmak MyCustomView foo = (MyCustomView) findViewById(R.id.foo);?
Jeremy Logan

3
Aynı sorunu yaşadım, benim durumumda seti unutmuştumContentView () .. XD
Tom Brito

Vogella.com'da böyle şeyler yapmanın güzel bir örneği var: vogella.com/articles/AndroidCustomViews/article.html
Wolkenjaeger

27

Aynı problemi yaşıyorum çünkü özel görüşümde yapıcıyı geçersiz kıldım ama attrs parametresi olmadan süper yükleniciyi çağırdım. Bu kopyala yapıştır)

Önceki kurucu sürümüm:

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

Şimdi sahibim:

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

Ve bu işe yarıyor!


Burada aynı sorun. Bu arada benim için de bir kopyala yapıştır hatasıydı.
KurtCobain

Bana da aynı şey oldu. Stackoverflow'daki en doğru cevap. AttributeSet attrs eklendiğinde, her şey yolunda.
spikeyang

Sanırım hepimiz aynı öğreticiye özel görünümle baktık;) bu hata bana 0,5 saat anlamsız hata ayıklama yaptı ...
KrwawyKefir

Bu benim için de çalıştı! Bununla epey bir süre mücadele ettim. Teşekkürler!
us_david

18

Ben de aynı sorunu yaşadım. Benim hatam şuydu: yazdım

        LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View layout=inflater.inflate(R.layout.dlg_show_info, null);
        alertDlgShowInfo.setView(layout);
        TableRow trowDesc=(TableRow)findViewById(R.id.trowDesc);

ve görünümü bir XML dosyasından "yüklemek" için bir şişirici kullandığım için, son satır yanlıştı. Çözmek için şunu yazmam gerekiyordu:

TableRow trowDesc=(TableRow)layout.findViewById(R.id.trowDesc);

Birisinin aynı sorunu yaşaması durumunda çözümümü yazdım.


Ahbap, sen bir dahisin.
SO'da

Bu benim için de sorun oldu. Vay canına, ne kadar ... Bunu kendi başıma çözmem günlerimi alırdı. Teşekkür ederim!
poshaughnessy

18

Görünüşe göre çeşitli nedenler var. Eclipse'de benzer bir sorunu çözmek için "Temizle ..." kullandım. (FindViewByID daha önce çalışmıştı ve nedense boş döndürmeye başladı.)


1
Görünüşe göre, temel sorun, R.java kimliklerinin bir şekilde kırılması veya belki de güncellenmemesidir. Bunu sadece kimliklerle değil, başka durumlarda da fark ettim, örneğin bir TextView'da görüntülenen yanlış dizge vb. Yine de bunun neden olduğunu gerçekten bilmiyorum.
denizanası

Bu bana çok uzun süre keder veriyordu - bir temizlik gerçekten benim için düzeltti.
Nicholas MT Elliott

1
Gerçekten temizleyin. Vay canına, bu berbat!
Tim Büthe

11

Aynı sorun ama farklı çözüm: Aramadım

setContentView(R.layout.main)

ÖNCE burada belirtildiği gibi görünümü bulmaya çalıştım


Bence mevcut ilgili görüş yerine başka bir bakış açısıyla bir öğe alıyorsanız çözüm budur.
StarCub

4

Birden çok düzen sürümünüz varsa (ekran yoğunluklarına, SDK sürümlerine bağlı olarak) hepsinin aradığınız öğeyi içerdiğinden emin olun.


2

Benim durumumda findViewById null döndürüyordu çünkü özel görünümüm ana XML'de şöyle görünüyordu:

        <com.gerfmarquez.seekbar.VerticalSeekBar  
            android:id="@+id/verticalSeekBar"
            android:layout_width="wrap_content" 
            android:layout_height="fill_parent" 
            />

ve xmlns şeylerini eklediğimde şöyle çalıştığını öğrendim:

        <com.gerfmarquez.seekbar.VerticalSeekBar  
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/verticalSeekBar"
            android:layout_width="wrap_content" 
            android:layout_height="fill_parent" 
            />

2

İfadenin setContentView(R.layout.main)ifadeden önce findViewById(...)çağrıldığından emin olun ;


1

Benim için sorun, res klasörünü proje Ayarlarında Java Derleme Yolundaki Kaynağa eklediğimde çözüldü.


1

Düzen XML aracılığıyla özel bir Görünüm eklediğimde ve daha sonra uygulamanın başka bir yerine bir geri arama eklemeye çalıştığımda aynı sorunla karşılaştım ...

Özel bir görünüm oluşturdum ve bunu "layout_main.xml" dosyama ekledim

public class MUIComponent extends SurfaceView implements SurfaceHolder.Callback {
    public MUIComponent (Context context, AttributeSet attrs ) {
        super ( context, attrs );
    }
    // ..
}

Ve ana Aktivitede bazı geri çağrılar eklemek ve XML'den UI öğelerine referanslar almak istedim.

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // ...

        MUIInitializer muiInit = new MUIInitializer();
        muiInit.setupCallbacks(this);
        muiInit.intializeFields(this);
    }       
}

Başlatıcı hiçbir şey yapmıyordu, ancak özel görünümde (MUIComponent) veya diğer özel olmayan UI öğelerinde yapmaya çalıştığı herhangi bir değişiklik , uygulamada görünmüyordu.

public class MUIInitializer {

    // ...

    public void setupCallbacks ( Activity mainAct ) {


        // This does NOT work properly
        // - The object instance returned is technically an instance of my "MUICompnent" view
        //   but it is a *different* instance than the instance created and shown in the UI screen
        // - Callbacks never get triggered, changes don't appear on UI, etc.
        MUIComponent badInst = (MUIComponent) mainAct.findViewById(R.id.MUIComponent_TESTSURF);


        // ...
        // This works properly

        LayoutInflater inflater = (LayoutInflater) mainAct.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View inflatedLayout = inflater.inflate ( R.layout.activity_main, null );

        MUIComponent goodInst = (MUIComponent) inflatedLayout.findViewById(R.id.MUIComponent_TESTSURF);


        // Add callbacks
        // ...
    }

}

"BadInst" ve "goodInst" arasındaki fark şudur:

  • badInst, Aktivitenin findViewByID'sini kullanır
  • goodInst düzeni şişirir ve aramayı yapmak için şişirilmiş düzeni kullanır

Dikkat Çekici Vincent aynı çözümü vardır ... ve onun cevabı en kısa ... 1 onun yerine :)
DevByStarlight

1

Bu Wear için özel bir bileşenle başıma geldi, ancak genel bir tavsiye. Bir Saplama kullanıyorsanız (benim kullandığım gibi WatchViewStub), aramayı findViewById()hiçbir yere yapamazsınız . Saplamanın içindeki her şey önce şişirilmelidir, bu hemen sonra olmaz setContentView(). Bu nedenle, bunun olmasını beklemek için şöyle bir şey yazmalısınız:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_wear);
    final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
    stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
        @Override
        public void onLayoutInflated(WatchViewStub stub) {
            myCustomViewInst = (MyCustomView) findViewById(R.id.my_custom_view);
            ...

0

Benim sorunum bir yazım hatasıydı. Yerine android.id(nokta) yazmıştım android:id. : P

Görünüşe göre benim özel xml bileşenimde sözdizimi denetimi yok. :(


0

Aynı sorunu yaşadım.

Birkaç çocuklu bir düzenim vardı. Birinin yapıcısından diğer alt öğeye (context.findViewById kullanarak) başvuru almaya çalışıyordum. Çalışmıyordu çünkü ikinci çocuk düzende daha fazla tanımlanmıştı.

Bunu şu şekilde çözdüm:

setContentView(R.layout.main);
MyView first = findViewById(R.layout.first_child);
first.setSecondView(findViewById(R.layout.second_child));

Çocukların sıralaması zıt olsaydı da işe yarardı ama sanırım genel olarak yukarıdaki gibi yapılmalı.


1
Genelde a'nın findViewByIdyapıcısında kullanmamalı View, bunun yerine başlatma kodunu koymalısınız OnFinishInflate?
Sanjay Manohar

0

findViewById()Yöntem bazen döner nulldüzeni kök hiçbir olduğundaandroid:id niteliğini. Düzen xml dosyası oluşturmaya yönelik Eclipse sihirbazı android:id, kök öğe için özniteliği otomatik olarak oluşturmaz .


0

Benim durumumda görüş, onu aramaya çalıştığım görünümde DEĞİL ebeveynde değildi. Dolayısıyla çocuk görünümünde aramak zorunda kaldım:

RelativeLayout relLayout = (RelativeLayout) this.getParent();
View view1 = relLayout.findViewById(R.id.id_relative_layout_search);

0

'Temiz' seçeneği benim için çalıştı.

Benim durumumda temel neden, kaynak kodun bir ağ paylaşımında bulunması ve iş istasyonumun ve dosya sunucumun doğru şekilde senkronize edilmemesi ve 5 saniye kaymasıdır. Eclipse tarafından oluşturulan dosyalardaki zaman damgaları geçmiştedir (çünkü bunlar dosya sunucusu tarafından atanırlar) iş istasyonunun saatini yazarak Eclipse'in oluşturulan ve kaynak dosyalar arasındaki bağımlılıkları yanlış bir şekilde çözmesine neden olur. Bu durumda, yanlış zaman damgalarına bağlı artımlı bir derleme yerine tam bir yeniden oluşturmaya zorladığı için 'temiz' işe yarıyor gibi görünür.

İş istasyonumdaki NTP ayarlarını düzelttikten sonra, sorun bir daha asla oluşmadı. Uygun NTP ayarları olmadan, saatler hızla değiştiğinden birkaç saatte bir gerçekleşebilirdi.


Bunu yukarıdaki cevabın yorumuna eklemelisiniz
Trung Nguyen

0

Dikkat edilmesi gereken cevaplara başka bir önemsiz hata eklemek için:

Doğru düzen XML dosyasını gerçekten düzenlediğinizi kontrol edin ...


0

aynı sorunu yaşadım çünkü tüm düzen klasörlerimdeki görünüm kimliğini güncellemeyi unuttum.

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.