findViewByID zwraca null


251

Po pierwsze: tak, przeczytałem wszystkie pozostałe wątki na ten temat. I nie tylko te z tej strony ... (widzisz, jestem trochę sfrustrowany)

Większość z nich zawiera porady, których należy używać android:idzamiast tylko idw pliku XML. Zrobiłem.

Nauczyłem się od innych, że View.findViewByIddziała inaczej niż Activity.findViewById. Ja też sobie z tym poradziłem.

W moim location_layout.xmlużywam:

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

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

W swojej działalności wykonuję:

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

i w mojej niestandardowej klasie widoku:

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

który zwraca null. Dzięki temu moja aktywność działa dobrze. Więc może to ze względu na Activity.findViewByIdi View.findViewByIdróżnic. Zapisałem więc kontekst przekazany lokalnie do konstruktora widoku celnego i próbowałem:

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

który również wrócił null.

Następnie zmieniłem widoku niestandardowego rozszerzenia ViewGroupzamiast Viewi zmienił location_layout.xmlpozwolić TextViewbyć bezpośrednim dziecko mojego widoku niestandardowego, tak że View.findViewByIdpowinno działać jak przypuszczano. Zaskocz: nic nie rozwiązało.

Co do cholery robię źle?

Będę wdzięczny za wszelkie komentarze.


6
Może się to zdarzyć, jeśli projekt jest również uszkodzony. Naprawiłem to, czyszcząc projekt
Pacerier

1
przeszedł niepoprawny widok kontekstowy dzięki
izzy

1
@Pacerier dziękuję. które rozwiązało mój problem. Zaczynam nienawidzić programowania na Androida w Xamarinie)
Artiom

@Pacerier „Clean project” rozwiązał również mój problem. Wygląda na to, że Dropbox zepsuł projekt.
Kohki Mametani

Odpowiedzi:


271

która zwraca null

Być może dlatego, że dzwonisz za wcześnie. Poczekaj, aż onFinishInflate(). Oto przykładowy projekt demonstrujący niestandardowy Viewdostęp do jego zawartości.


67
O MÓJ BOŻE! Nie mogę uwierzyć, że spędzam dni na czymś tak trywialnym. Przeniosłem setContentView () nad wywołanie findViewById () i to nie pomogło. dzięki!
agentcurry

2
@CommonsCzy to prawidłowy projekt? Nigdzie nie widzę onFinishInflate w github.com/commonsguy/cw-advandroid/tree/master/Animation/…
likejudo

1
@ likejiujitsu: Mogło to mieć już w 2010 roku. Zaktualizowałem link do nowszego projektu, który ma onFinishInflate().
CommonsWare,

3
Mam mój setContentView wywołany przed findViewById i nadal jest pusty. Mam na
myśli EditText

1
Zawsze linkuj do stałych zatwierdzeń GitHub (np. Github.com/commonsguy/cw-omnibus/tree/… ) i nigdy nie usuwaj
repozytoriów ani baz danych

145

Być może dzwonisz findViewByIdprzed telefonem setContentView? W takim przypadku spróbuj zadzwonić findViewById PO telefonowaniusetContentView


1
Tak łatwo popełnić błąd, ale niestety to właśnie zrobiłem. Debuger nie ma sensu, ponieważ powiedział, że błąd wystąpił w mojej nowej linii docelowej, a nie w rzeczywistej nowej aktywności, do której dzwoniłem. Dzięki!
edude05

6
Tak naprawdę miałem ten błąd, ponieważ dzwoniłem do setContentView, wskazując niewłaściwy widok ... niestety kompilator nie wychwytuje tego typu błędu.
HeatfanJohn

Tak, przez pomyłkę usunąłem setContentView i nie rozumiem, dlaczego mój program zaczął się kruszyć.
Ronen Festinger

100

Upewnij się, że nie masz wielu wersji swojego układu dla różnych gęstości ekranu. Natknąłem się na ten problem podczas dodawania nowego identyfikatora do istniejącego układu, ale zapomniałem zaktualizować wersję HDpi. Jeśli zapomnisz zaktualizować wszystkie wersje pliku układu, będzie on działał dla niektórych gęstości ekranu, ale nie dla innych.


8
DZIĘKI! To było to. (W moim przypadku mam wiele wersji dla różnych wersji Androida). Cały czas o tym zapominam, chociaż umieszczam gigantyczny komentarz na górze i na dole każdego pliku układu. Chciałbym, żeby kompilator zrobił błąd lub duże ostrzeżenie, jeśli tak się stanie.
tiktak

Ding ding ding, dziękuję bardzo! Pochylałem mózg nad tym lolem
Zach.

21

FindViewById może mieć wartość NULL, jeśli wywołasz niewłaściwy superkonstruktor w widoku niestandardowym. Tag ID jest częścią attrs, więc jeśli zignorujesz attrs, usuniesz identyfikator.

To by było złe

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

To jest poprawne

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

1
Dziękuję bardzo panu! Jestem tak nieostrożny, że nawet wątpiłem, czy coś jest nie tak z moim IDE. Jak dobrze, że spotkałem twoją odpowiedź.
EffectiveMatrix

Popełniłem ten błąd, tworząc własny widok. Dziękuję, repkap11.
Andrew F.,

15

W moim przypadku miałem 2 działania w moim projekcie main.xmli main2.xml. Od samego początku main2było kopią main, i wszystko działało dobrze, dopóki nie dodałem nowy TextViewdo main2, więc R.id.textview1stał się dostępny dla reszty aplikacji. Następnie próbowałem pobrać go za pomocą standardowego wywołania:

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

i zawsze było zero. Okazało się, że w onCreatekonstruktorze nie tworzyłem instancji main2, ale drugą. Miałem:

setContentView(R.layout.main);

zamiast

setContentView(R.layout.main2);

Zauważyłem to po przyjeździe tutaj na stronie.


14

Oprócz klasycznych przyczyn wymienionych w innym miejscu:

  • Upewnij się, że dzwoniłeś setContentView()wcześniejfindViewById()
  • Upewnij się, że idchcesz mieć widok lub układ, który podałeśsetContentView()
  • Upewnij się, że idnie jest przypadkowo powielony w różnych układach

Znalazłem jeden dla niestandardowych widoków w standardowych układach, który jest sprzeczny z dokumentacją:

Teoretycznie możesz utworzyć niestandardowy widok i dodać go do układu ( patrz tutaj ). Odkryłem jednak, że w takich sytuacjach czasami idatrybut działa dla wszystkich widoków w układzie oprócz tych niestandardowych. Rozwiązaniem, którego używam jest:

  1. Zastąp każdy widok niestandardowy FrameLayouto takich samych właściwościach układu, jakie chcesz mieć w widoku niestandardowym. Daj temu odpowiedni id, powiedzmy frame_for_custom_view.
  2. W onCreate:

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

    co umieszcza niestandardowy widok w ramce.


Pomogło mi to: „Upewnij się, że identyfikator, którego szukasz, znajduje się w widoku lub układzie podanym dla setContentView ()”. Co jednak zrobić, gdy jest to podview? Próbowałem uzyskać widok rodzica, a następnie wykonaj parentView.findById (), ale nadal zwraca wartość null
NaturalBornCamper

@naturalborncamper, jeśli opublikujesz osobne pytanie z przykładowym kodem, popatrzę na to.
Neil Townsend

Dzięki Neil, już napisałem i ktoś wskazał lepszy sposób na zrobienie tego, chociaż nie działa to dokładnie tak, jak powinno być, więc musiałem użyć innej strategii: stackoverflow.com/questions/47955376/...
NaturalBornCamper

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

6

Odpowiedź dla tych, którzy używają ExpandableListView i napotkasz to pytanie na podstawie jego tytułu.

Wystąpił ten błąd podczas próby pracy z TextView w widoku potomnym i grupowym w ramach implementacji ExpandableListView.

W implementacjach metod getChildView () i getGroupView () można użyć czegoś takiego jak poniżej.

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

Znalazłem to tutaj .


5

Jestem całkiem nowy w Android / Eclipse, przez pomyłkę dodałem rzeczy interfejsu użytkownika activity_main.xmlzamiast fragment_main.xml. Zajęło mi to kilka godzin, żeby to rozgryźć ...


5

FWIW, nie widzę, aby ktokolwiek rozwiązał to w taki sam sposób, jak potrzebowałem. Brak skarg w czasie kompilacji, ale w czasie wykonywania otrzymywałem zerowy widok i wzywałem rzeczy we właściwej kolejności. Oznacza to findViewById () po setContentView (). Problem okazał się, że mój widok jest zdefiniowany w content_main.xml, ale w mojej activity_main.xml brakowało mi tej jednej instrukcji:

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

Kiedy dodałem to do activity_main.xml, nie ma już NullPointer.


Problem z kopiowaniem wklejania fragmentu polega na tym, że czasami zapominasz o zmianie niektórych rzeczy ... będąc poprawnym układem, aby zawyżyć jedną z nich. Dzięki!
Pablo Quemé,

3

Miałem ten sam problem. Korzystałem z biblioteki innej firmy, która pozwala zastąpić ich adapter dla GridView i określić własny układ dla każdej komórki GridView.

W końcu zrozumiałem, co się dzieje. Zaćmienie nadal używało pliku xml układu biblioteki dla każdej komórki w GridView, chociaż nie dawało tego żadnej wskazówki. W moim niestandardowym adapterze oznaczało, że korzysta z zasobu xml z mojego własnego projektu, chociaż w czasie wykonywania tak nie było.

Więc upewniłem się, że moje niestandardowe układy i identyfikatory XML różnią się od tych, które wciąż siedzą w bibliotece, wyczyściłem projekt, a następnie zacząłem czytać prawidłowe niestandardowe układy, które były w moim projekcie.

Krótko mówiąc, należy zachować ostrożność, jeśli przesłonisz adapter biblioteki innej firmy i określisz własny układ xml dla adaptera do użycia. Jeśli układ w projekcie ma taką samą nazwę pliku jak w bibliotece, możesz napotkać naprawdę trudny do znalezienia błąd!


3

W moim szczególnym przypadku próbowałem dodać stopkę do ListView. Następujące wywołanie funkcji onCreate () zwracało wartość null.

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

Zmiana tego ustawienia, aby nadmuchać widok stopki zamiast znajdowania go według ID, rozwiązała ten problem.

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

2

W moim przypadku korzystałem z ExpandableListView i ustawiłem android:transcriptMode="normal". Powodowało to zniknięcie kilku dzieci w rozszerzalnej grupie i uzyskiwałem wyjątek NULL, gdy tylko przewijałem listę.


2

Dla mnie miałem dwa układy XML dla tej samej aktywności - jeden w trybie pionowym i jeden w układzie poziomym. Oczywiście zmieniłem identyfikator obiektu w xml krajobrazowym, ale zapomniałem dokonać tej samej zmiany w wersji portretowej. Upewnij się, że jeśli zmienisz jeden, zrobisz to samo z drugim xml, inaczej nie pojawi się błąd, dopóki go nie uruchomisz / nie debugujesz i nie będzie mógł znaleźć identyfikatora, którego nie zmieniłeś. Och głupie błędy, dlaczego musisz mnie tak karać?


2

Ustaw zawartość działania z zasobu układu. tj., setContentView(R.layout.basicXml);


2

Oprócz powyższych rozwiązań
tools:context=".TakeMultipleImages" upewniasz się, że układ ma taką samą wartość w pliku mainfest.xml:
android:name=".TakeMultipleImages"dla tego samego elementu aktywności. ma to miejsce, gdy używasz funkcji kopiuj i wklej, aby utworzyć nową aktywność


2

Mam ten sam problem, ale myślę, że warto się z wami podzielić. Jeśli musisz znaleźćViewById w niestandardowym układzie, na przykład:

public class MiniPlayerControllBar extends LinearLayout {
    //code
}

nie można uzyskać widoku w konstruktorze. Powinieneś wywołać findViewById po zawyżeniu widoku. Jest to metoda, którą można zastąpićonFinishInflate


2

Chciałem tu wrzucić moją konkretną sprawę. Może pomóc komuś w dalszej linii.

Użyłem tej dyrektywy w moim XML UI dla Androida w następujący sposób:

Widok rodzica:

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

Widok dziecka (przycisk ponawiania):

<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) zawsze zwraca wartość null. Ale jeśli przeniosłem identyfikator z widoku potomnego do tagu dołączania, zaczął on działać.

Naprawiony rodzic:

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

Naprawiono dziecko:

<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

Mój przypadek jest taki jak wyżej, żadne rozwiązania nie działały. Zakładam, że mój widok był zbyt głęboko w hierarchii układu. Przeniosłem go o jeden poziom wyżej i nie był już zerowy.


Mam ten sam problem, można też znaleźć jeden poziom wyżej .. to dość denerwujące i chciałbym wiedzieć, dlaczego tak się dzieje, ponieważ nie mogę zrobić mojego menu tak, jak chcę
NaturalBornCamper

Cóż, głębokie hierarchie układów są anty-wzorcowe, prawie zawsze istnieje czystsze rozwiązanie. Mówisz o menu przepełnienia na pasku narzędzi lub szufladzie nawigacji?
Deividas Strioga,

Szuflada nawigacji, faktycznie napisałem już inne pytanie, z wyjątkiem tego, że dodanie elementu menu w grupie nie działa, po prostu dodaje je na końcu wszystkich elementów: stackoverflow.com/questions/47955376/…
NaturalBornCamper

1

W moim przypadku zawyżyłem układ, ale widoki dzieci wracają do zera. Pierwotnie miałem to:

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

Kiedy jednak zmieniłem go na następujący, zadziałało:

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

Kluczem było konkretne odniesienie do już zawyżonego układu, aby uzyskać widoki dziecka. To znaczy, aby dodać footerView:

  • footerView .findViewById ...

0

Z mojego doświadczenia wynika, że ​​może się to zdarzyć również wtedy, gdy twój kod jest wywoływany po OnDestroyView (gdy fragment znajduje się na tylnym stosie). Jeśli aktualizujesz interfejs użytkownika na wejściu z BroadCastReceiver, powinieneś sprawdzić, czy tak jest .


0

NAPEŁNIJ UKŁAD !! (który zawiera identyfikator)

W moim przypadku findViewById () zwrócił null, ponieważ układ, w którym element został zapisany, nie został zawyżony ...

Na przykład. fragment_layout.xml

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

findViewById (R.id.listview) zwrócił wartość null, ponieważ nie wykonałem inflater.inflate (R.layout.fragment_layout, ..., ...); przed tym.

Mam nadzieję, że ta odpowiedź pomoże wam wszystkim.



0

findViewById może również zwrócić null, jeśli znajdujesz się we fragmencie. Jak opisano tutaj: findViewById we fragmencie

Powinieneś wywołać metodę getView (), aby zwrócić widok najwyższego poziomu wewnątrz fragmentu. Następnie możesz znaleźć elementy układu (przyciski, widoki tekstu itp.)


0

Próbowałem wszystkiego powyższego, nic nie działało .. więc musiałem ustawić statyczny obraz ImageView, public static ImageView texture; a potem texture = (ImageView) findViewById(R.id.texture_back);nie sądzę, że to dobre podejście, ale to naprawdę działało w moim przypadku :)


przepraszam, myślę, że statyczny widok to zły pomysł
vuhung3990,

0

W moim przypadku findViewById zwrócił wartość null, gdy przeniosłem wywołanie z obiektu nadrzędnego do obiektu adaptera utworzonego przez obiekt nadrzędny. Po wypróbowaniu wymienionych tutaj sztuczek bezskutecznie przeniosłem findViewById z powrotem do obiektu nadrzędnego i przekazałem wynik jako parametr podczas tworzenia instancji obiektu adaptera. Na przykład zrobiłem to w obiekcie nadrzędnym:

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

Następnie przekazałem hdSpinner jako parametr podczas tworzenia obiektu adaptera:

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

0

Awaria dla mnie, ponieważ jedno z pól w moim identyfikatorze aktywności było zgodne z identyfikatorem w innej aktywności. Naprawiłem to, podając unikalny identyfikator.

W moim loginActivity.xml pole hasła to „hasło”. W mojej działalności rejestracyjnej właśnie to naprawiłem, podając id r_password, a następnie nie zwrócił obiektu zerowego:

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

0

Napotkałem podobny problem, gdy próbowałem zrobić niestandardowy widok dla ListView.

Rozwiązałem to po prostu przez zrobienie tego:

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

Sposoby debugowania i znalezienia problemu:

  • Skomentuj wszystkie findViewById w swojej aktywności.
  • Skomentuj wszystko oprócz onCreate i setContentView
  • Uruchom projekt i sprawdź, czy ustawiony jest jakikolwiek układ

W moim przypadku korzystałem z activity_main.xml zarówno w module aplikacji, jak i module biblioteki. Więc kiedy wykonałem powyższe kroki, zamiast układu, który zaprojektowałem w bibliotece, układ wewnątrz modułu aplikacji został zawyżony.

Więc zmieniłem nazwę pliku activity_main.xml na activity_main_lib.xml.

Więc upewnij się, że nie mają żadnych zduplikowane nazwy układu w całym projekcie .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.