findViewByID restituisce null


252

Prima di tutto: sì, ho letto tutti gli altri thread su questo argomento. E non solo quelli di questo sito ... (vedi, sono un po 'frustrato)

La maggior parte di essi viene fornita con il consiglio di utilizzare android:idanziché solo idnel file XML. L'ho fatto.

Da altri, ho imparato, che View.findViewByIdfunziona diversamente da Activity.findViewById. Ho gestito anche quello.

Nel mio location_layout.xml, io uso:

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

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

Nella mia attività faccio:

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

e nella mia classe di visualizzazione personalizzata:

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

che ritorna null. In questo modo, la mia attività funziona bene. Quindi forse è a causa della Activity.findViewByIde View.findViewByIddifferenze. Quindi ho archiviato il contesto passato al costruttore della vista doganale localmente e ho provato:

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

che ha anche restituito null.

Poi, ho cambiato il mio visualizzazione personalizzata per estendere ViewGroupinvece Viewe cambiato il location_layout.xmllasciare che il TextViewsia un figlio diretto della mia visualizzazione personalizzata, in modo che la View.findViewByIddovrebbe funzionare come supposto. Suprise: non ha risolto nulla.

Cosa diavolo sto facendo di sbagliato?

Apprezzerò qualsiasi commento.


6
Ciò può verificarsi se anche il progetto è danneggiato. L'ho risolto pulendo il progetto
Pacerier,

1
passato vista di contesto sbagliata grazie
izzy

1
@Pacerier grazie. che ha risolto il mio problema. Comincio a odiare la programmazione Android in Xamarin)
Artiom,

@Pacerier "Clean project" ha risolto anche il mio problema. Sembra che Dropbox abbia corrotto il progetto.
Kohki Mametani,

Risposte:


271

che restituisce null

Forse perché lo chiami troppo presto. Aspetta fino a onFinishInflate(). Ecco un progetto di esempio che dimostra un Viewaccesso personalizzato al suo contenuto.


67
OH MIO DIO! Non riesco a credere che passo giorni in qualcosa di così banale. Ho spostato setContentView () sopra la chiamata findViewById () e quello ha funzionato. Grazie!
agentcurry,

2
@CommonsWare che il progetto corretto? Non vedo suFinishInflate da nessuna parte in github.com/commonsguy/cw-advandroid/tree/master/Animation/…
likejudo,

1
@likejiujitsu: Potrebbe averlo già fatto nel 2010. Ho aggiornato il link a un nuovo progetto che ha onFinishInflate().
CommonsWare,

3
Ho chiamato il mio setContentView prima di findViewById ed è ancora nullo. Mi riferisco a un EditText
Neon Warge il

1

145

Forse, stai chiamando findViewByIdprima di chiamare setContentView? In tal caso, prova a chiamare findViewById DOPO la chiamatasetContentView


1
È stato un errore così facile ma, sfortunatamente, è quello che avevo fatto. Il debugger è inutile poiché ha detto che l'errore era nella mia nuova linea di intenti, non nella nuova attività che stavo chiamando. Grazie!
edude05,

6
In realtà ho avuto questo errore perché stavo chiamando setContentView puntando alla vista sbagliata ... sfortunatamente il compilatore non rileva questo tipo di errore.
Heatfan John,

Sì, ho eliminato setContentView per errore e non ho capito perché il mio programma ha iniziato a rompersi.
Ronen Festinger,

100

Assicurati di non avere più versioni del layout per diverse densità dello schermo. Ho riscontrato questo problema una volta quando ho aggiunto un nuovo ID a un layout esistente ma ho dimenticato di aggiornare la versione di hdpi. Se si dimentica di aggiornare tutte le versioni del file di layout, funzionerà con alcune densità dello schermo ma non con altre.


8
GRAZIE! Questo è stato. (Nel mio caso ho più versioni per diverse versioni di Android). Me ne dimentico sempre, anche se ho inserito un commento gigantesco in cima e in fondo a ogni file di layout. Vorrei che il compilatore facesse un errore o un grosso avvertimento se ciò accadesse.
tiktak,

Ding ding ding, grazie mille! Stavo piegando il mio cervello per questo lol
Zach

21

FindViewById può essere nullo se si chiama il super costruttore errato in una vista personalizzata. Il tag ID fa parte di attr, quindi se si ignora attr, si elimina l'ID.

Questo sarebbe sbagliato

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

Questo è corretto

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

1
Grazie mille signore! Sono così negligente, ho anche solo dubitato che ci fosse qualcosa di sbagliato nel mio IDE. Che fortuna incontrare la tua risposta.
EffectiveMatrix,

Ho fatto questo errore quando ho creato la mia vista personalizzata. Grazie, repkap11.
Andrew F.

15

Nel mio caso, avevo 2 attività nel mio progetto main.xmle main2.xml. Fin dall'inizio, main2era una copia main, e tutto funzionava bene, fino a quando ho aggiunto nuovo TextViewa main2, in modo che il R.id.textview1è diventato disponibile per il resto della app. Quindi ho provato a recuperarlo chiamando standard:

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

ed era sempre nullo. Si è scoperto che nel onCreatecostruttore non ho istanziato main2, ma l'altro. Avevo:

setContentView(R.layout.main);

invece di

setContentView(R.layout.main2);

L'ho notato dopo essere arrivato qui, sul sito.


14

Accanto alle cause classiche, menzionate altrove:

  • Assicurati di aver chiamato setContentView()primafindViewById()
  • Assicurati che ciò idche desideri sia nella vista o nel layout a cui hai datosetContentView()
  • Assicurarsi che idnon sia duplicato accidentalmente in diversi layout

Ce n'è uno che ho trovato per visualizzazioni personalizzate nei layout standard, che va contro la documentazione:

In teoria puoi creare una vista personalizzata e aggiungerla a un layout ( vedi qui ). Tuttavia, ho scoperto che in tali situazioni, a volte l' idattributo funziona per tutte le viste nel layout tranne quelle personalizzate. La soluzione che utilizzo è:

  1. Sostituisci ogni vista personalizzata con una FrameLayoutcon le stesse proprietà di layout che desideri avere la vista personalizzata. Dagli un appropriato id, diciamo frame_for_custom_view.
  2. In onCreate:

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

    che inserisce la vista personalizzata nella cornice.


Questo mi ha aiutato: "Assicurati che l'id che desideri sia nella vista o nel layout che hai assegnato a setContentView ()". Cosa fare quando si tratta di una sottoview? Ho provato a ottenere la vista padre quindi esegui parentView.findById () ma sta ancora restituendo null
NaturalBornCamper

@naturalborncamper se pubblichi una domanda separata con un codice di esempio, lo darò.
Neil Townsend,

Grazie Neil, ho già pubblicato e qualcuno ha indicato un modo migliore per farlo, anche se non funziona esattamente come dovrebbe essere, quindi ho dovuto usare una strategia diversa: stackoverflow.com/questions/47955376/…
NaturalBornCamper

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

6

Una risposta per coloro che utilizzano ExpandableListView e si imbattono in questa domanda in base al titolo.

Ho riscontrato questo errore nel tentativo di lavorare con TextViews nelle visualizzazioni figlio e gruppo come parte di un'implementazione ExpandableListView.

È possibile utilizzare qualcosa di simile al seguente nelle implementazioni dei metodi getChildView () e getGroupView ().

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

L'ho trovato qui .


5

Sono abbastanza nuovo su Android / Eclipse, per errore ho aggiunto le cose dell'interfaccia utente activity_main.xmlinvece di fragment_main.xml. Mi ci sono volute alcune ore per capirlo ...


5

FWIW, non vedo che nessuno abbia risolto tutto nello stesso modo in cui avevo bisogno. Nessuna lamentela al momento della compilazione, ma stavo ottenendo una visione nulla in fase di esecuzione e chiamando le cose nell'ordine corretto. Cioè, findViewById () dopo setContentView (). Il problema si è scoperto che la mia vista è definita in content_main.xml, ma nel mio activity_main.xml mi mancava questa affermazione:

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

Quando l'ho aggiunto a activity_main.xml, non più NullPointer.


Il problema con la copia e incolla di un frammento è che a volte ti dimentichi di cambiare alcune cose ... essendo il layout corretto per gonfiarne una. Grazie!
Pablo Quemé,

3

Ho avuto lo stesso problema. Stavo usando una libreria di terze parti che ti consente di sostituire il loro adattatore per un GridView e di specificare il tuo layout per ogni cella GridView.

Alla fine ho capito cosa stava succedendo. Eclipse stava ancora usando il file xml di layout della libreria per ogni cella in GridView, anche se non ne forniva alcuna indicazione. Nel mio adattatore personalizzato, indicava che stava usando la risorsa xml del mio progetto, anche se in fase di esecuzione non lo era.

Quindi quello che ho fatto è stato assicurarmi che i miei layout e ID XML personalizzati fossero diversi da quelli ancora presenti nella libreria, ho pulito il progetto e poi ha iniziato a leggere i layout personalizzati corretti presenti nel mio progetto.

In breve, fai attenzione se esegui l'override dell'adattatore di una libreria di terze parti e specifichi il tuo xml di layout per l'adattatore da utilizzare. Se il layout all'interno del tuo progetto ha lo stesso nome di file di quello nella libreria, potresti riscontrare un bug davvero difficile da trovare!


3

Nel mio caso particolare, stavo cercando di aggiungere un piè di pagina a ListView. La seguente chiamata in onCreate () stava restituendo null.

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

Modificarlo per gonfiare la vista a piè di pagina invece di trovarla tramite ID ha risolto il problema.

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

2

Nel mio caso, stavo usando ExpandableListView e avevo impostato android:transcriptMode="normal". Ciò stava causando la scomparsa di alcuni bambini nel gruppo espandibile e ho usato l'eccezione NULL quando mai ho usato scorrere l'elenco.


2

Per me avevo due layout XML per la stessa attività: uno in modalità verticale e uno in orizzontale. Ovviamente avevo cambiato l'id di un oggetto nel paesaggio xml ma avevo dimenticato di fare lo stesso cambiamento nella versione verticale. Assicurati che se cambi uno fai lo stesso con l'altro xml o non otterrai un errore fino a quando non lo esegui / esegui il debug e non trovi l'ID che non hai modificato. Oh stupidi errori, perché mi devi punire così?


2

Imposta il contenuto dell'attività da una risorsa di layout. cioè., setContentView(R.layout.basicXml);


2

Oltre alle soluzioni precedenti, assicurati che
tools:context=".TakeMultipleImages" nel layout abbia lo stesso valore nel file mainfest.xml:
android:name=".TakeMultipleImages"per lo stesso elemento di attività. si verifica quando si utilizza copia e incolla per creare una nuova attività


2

Ho lo stesso problema, ma penso che valga la pena condividerlo con voi ragazzi. Se devi trovareViewById nel layout personalizzato, ad esempio:

public class MiniPlayerControllBar extends LinearLayout {
    //code
}

non è possibile ottenere la vista nel costruttore. Dovresti chiamare findViewById dopo che la visualizzazione si è gonfiata. Il loro è un metodo che puoi ignorareonFinishInflate


2

Volevo solo inserire il mio caso specifico qui. Potrebbe aiutare qualcuno in fondo.

Stavo usando la direttiva nel mio XML dell'interfaccia utente Android in questo modo:

Vista principale:

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

Vista figlio (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) restituisce sempre null. Ma, se ho spostato l'ID dalla vista figlio nel tag include, ha iniziato a funzionare.

Genitore fisso:

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

Figlio fisso:

<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

Il mio caso non è come sopra, nessuna soluzione ha funzionato. Suppongo che la mia visione fosse troppo profonda nella gerarchia del layout. L'ho spostato di un livello e non era più nullo.


Ho lo stesso problema, un livello superiore può anche essere trovato .. è abbastanza fastidioso e mi piacerebbe sapere perché sta accadendo in quanto non riesco a rendere il mio menu come lo voglio
NaturalBornCamper

Bene le gerarchie di layout profonde sono anti pattern, quasi sempre c'è una soluzione più pulita. Stai parlando del menu di overflow nella barra degli strumenti o nel riquadro di navigazione?
Deividas Strioga,

Cassetto di navigazione, in realtà ho già pubblicato un'altra domanda, tranne per il fatto che l'aggiunta di una voce di menu all'interno di un gruppo non funziona, basta aggiungerla alla fine di tutti gli elementi: stackoverflow.com/questions/47955376/…
NaturalBornCamper

1

Nel mio caso avevo gonfiato il layout ma le viste secondarie stavano tornando nulle. Inizialmente avevo questo:

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

Tuttavia, quando l'ho cambiato nel seguente ha funzionato:

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

La chiave era fare specifico riferimento al layout già gonfiato per ottenere le viste figlio. Cioè, per aggiungere footerView:

  • footerView .findViewById ...

0

Nella mia esperienza, sembra che ciò possa accadere anche quando il tuo codice viene chiamato dopo OnDestroyView (quando il frammento è nello stack posteriore). Se stai aggiornando l'interfaccia utente sull'input da un BroadCastReceiver, dovresti verificare se questo è il caso .


0

GONFIA IL LAYOUT !! (che contiene l'id)

Nel mio caso findViewById () ha restituito null, perché il layout in cui è stato scritto l'elemento non è stato gonfiato ...

Per esempio. fragment_layout.xml

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

findViewById (R.id.listview) ha restituito null, perché non avevo eseguito inflater.inflate (R.layout.fragment_layout, ..., ...); prima di cio.

Spero che questa risposta aiuti alcuni di voi.


0

La mia soluzione era pulire semplicemente il progetto.


0

findViewById può anche restituire null se ti trovi all'interno di un frammento. Come descritto qui: findViewById in Fragment

È necessario chiamare getView () per restituire la vista di livello superiore all'interno di un frammento. Quindi puoi trovare gli elementi del layout (pulsanti, visualizzazioni di testo, ecc.)


0

Ho provato tutto quanto sopra non funzionava .. quindi ho dovuto rendere statico il mio ImageViewpublic static ImageView texture; e quindi texture = (ImageView) findViewById(R.id.texture_back);, non credo sia un buon approccio, ma ha funzionato davvero per il mio caso :)


scusa, penso che la visione statica sia una cattiva idea
vuhung3990

0

Nel mio caso, findViewById ha restituito null quando ho spostato la chiamata da un oggetto padre in un oggetto adattatore istanziato dal padre. Dopo aver provato i trucchi elencati qui senza successo, ho spostato findViewById nell'oggetto padre e ho passato il risultato come parametro durante l'istanza dell'oggetto adattatore. Ad esempio, l'ho fatto nell'oggetto genitore:

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

Quindi ho passato hdSpinner come parametro durante la creazione dell'oggetto adattatore:

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

0

Si è arrestato in modo anomalo perché uno dei campi nel mio ID attività corrispondeva con ID in un'altra attività. L'ho risolto dando un ID unico.

Nel mio ID campo loginActivity.xml password era "password". Nella mia attività di registrazione l'ho appena risolto dando id r_password, quindi non ha restituito un oggetto null:

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

0

Stavo affrontando un problema simile quando stavo provando a fare una vista personalizzata per a ListView.

L'ho risolto semplicemente facendo questo:

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

Modi per eseguire il debug e trovare il problema:

  • Commenta tutto findViewById nella tua attività.
  • Commenta tutto tranne onCreate e setContentView
  • Esegui il progetto e verifica se è stato impostato un layout

Nel mio caso, stavo usando activity_main.xml sia nel mio modulo app che nel mio modulo libreria. Quindi, quando ho eseguito i passaggi precedenti, invece del layout che ho progettato nella libreria, il layout all'interno del modulo dell'app è stato gonfiato.

Quindi ho cambiato il nome del file activity_main.xml in activity_main_lib.xml.

Quindi assicurati di non avere nomi di layout duplicati nell'intero progetto .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.