findViewByID retorna nulo

252

Primeiro de tudo: sim, eu li todos os outros tópicos sobre este tópico. E não apenas os deste site ... (veja, estou um pouco frustrado)

A maioria deles vem com o conselho de usar, em android:idvez de apenas idno arquivo XML. Eu fiz.

Aprendi que dos outros isso View.findViewByIdfunciona de maneira diferente Activity.findViewById. Eu lidei com isso também.

No meu location_layout.xml, eu uso:

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

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

Na minha atividade eu faço:

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

e na minha classe de exibição personalizada:

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

que retorna null. Fazendo isso, minha Atividade funciona bem. Então talvez seja por causa da Activity.findViewByIde View.findViewByIddiferenças. Então, eu armazenei o contexto passado para o construtor de exibição da alfândega localmente e tentei:

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

que também retornou null.

Então, eu mudei meu modo de exibição personalizado para estender ViewGroupvez Viewe mudou a location_layout.xmldeixar a TextViewser um filho direto do meu ponto de vista personalizado, de modo que o View.findViewByIddeve funcionar como deveria. Surpresa: não resolveu nada.

Então, o que diabos estou fazendo de errado?

Eu aprecio qualquer comentário.

Thomas
fonte
6
Isso pode ocorrer se o projeto também estiver corrompido. Eu fixo-lo limpando o projeto
Pacerier
1
passou contexto errado visão graças
izzy
1
@Pacerier obrigado. isso resolveu meu problema. Eu começo a odiar programação android em Xamarin)
Artiom
@Pacerier "Projeto limpo" também resolveu meu problema. Parece que o Dropbox corrompeu o projeto.
Kohki Mametani

Respostas:

271

que retorna nulo

Possivelmente porque você está ligando muito cedo. Espere até onFinishInflate(). Aqui está um projeto de amostra demonstrando um Viewacesso personalizado ao seu conteúdo.

CommonsWare
fonte
67
AMD! Não posso acreditar que passo dias em algo tão trivial. Movi setContentView () acima da chamada findViewById () e isso não foi possível. obrigado!
agentcurry
2
@CommonsVocê sabe que é o projeto correto? Eu não vejo qualquer lugar onFinishInflate em github.com/commonsguy/cw-advandroid/tree/master/Animation/...
likejudo
1
@likejiujitsu: Isso pode ter acontecido em 2010. Atualizei o link para um projeto mais recente onFinishInflate().
CommonsWare
3
Eu tenho meu setContentView chamado antes de findViewById e ainda é nulo. Estou referenciando um EditText
Neon Warge
1
Sempre link para commits GitHub fixos (por exemplo github.com/commonsguy/cw-omnibus/tree/... ) e nunca repos excluir ou rebase ;-)
Ciro Santilli郝海东冠状病六四事件法轮功
145

Possivelmente, você está ligando findViewByIdantes de ligar setContentView? Se for esse o caso, tente ligar findViewById APÓS ligarsetContentView

Bayram Boyraz
fonte
1
Um erro tão fácil de cometer, mas infelizmente foi isso que eu fiz. O depurador não serve para nada, pois ele disse que o erro estava na minha nova linha de intenção e não na nova atividade real que eu estava chamando. Obrigado!
precisa saber é o seguinte
6
Na verdade, eu tive esse erro porque estava chamando setContentView apontando para a exibição errada ... infelizmente o compilador não captura esse tipo de erro.
HeatfanJohn
Sim, excluí o setContentView por engano e não entendi por que meu programa começou a ser esmagado.
Ronen Festinger
100

Verifique se você não possui várias versões do seu layout para diferentes densidades de tela. Encontrei este problema uma vez ao adicionar um novo ID a um layout existente, mas esqueci de atualizar a versão do hdpi. Se você esquecer de atualizar todas as versões do arquivo de layout, ele funcionará para algumas densidades de tela, mas não para outras.

Joe
fonte
8
OBRIGADO! Foi isso. (No meu caso, tenho várias versões para diferentes versões do Android). Eu esqueço isso o tempo todo, apesar de colocar um comentário gigantesco na parte superior e inferior de cada arquivo de layout. Desejo que o compilador cometa um erro ou aviso grande se isso acontecer.
Tiktak
Ding ding ding, muito obrigado! Foi dobra meu cérebro ao longo deste lol
Zach
21

FindViewById pode ser nulo se você chamar o super construtor errado em uma exibição personalizada. A tag ID faz parte do attrs, portanto, se você ignorar o attrs, exclua o ID.

Isso seria errado

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

Isto está certo

public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context,attrs);
}
repkap11
fonte
1
Muito obrigado, senhor! Tão descuidado que eu sou, eu até duvidei que havia algo errado com o meu IDE. Que sorte encontrar sua resposta.
EffectiveMatrix
Cometi esse erro quando criei minha exibição personalizada. Obrigado, repkap11.
Andrew F.
15

No meu caso, eu tinha duas atividades no meu projeto, main.xmle main2.xml. Desde o início, main2era uma cópia main, e tudo funcionou bem, até que eu adicionei novo TextViewpara main2, assim que o R.id.textview1tornou-se disponível para o resto do aplicativo. Então tentei buscá-lo por chamada padrão:

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

e sempre foi nulo. Aconteceu que no onCreateconstrutor eu estava instanciando não main2, mas o outro. Eu tinha:

setContentView(R.layout.main);

ao invés de

setContentView(R.layout.main2);

Percebi isso depois que cheguei aqui, no site.

infografnet
fonte
14

Juntamente com as causas clássicas, mencionadas em outros lugares:

  • Verifique se ligou setContentView()antesfindViewById()
  • Certifique-se de que idvocê deseja estar na exibição ou no layout fornecidosetContentView()
  • Certifique-se de que idnão seja duplicado acidentalmente em diferentes layouts

Há uma que encontrei para visualizações personalizadas em layouts padrão, que vão contra a documentação:

Em teoria, você pode criar uma exibição personalizada e adicioná-la a um layout ( veja aqui ). No entanto, descobri que nessas situações, às vezes, o idatributo funciona para todas as visualizações no layout, exceto as personalizadas. A solução que eu uso é:

  1. Substitua cada visualização personalizada por uma FrameLayoutcom as mesmas propriedades de layout que você gostaria que a visualização personalizada tivesse. Dê um apropriado id, digamos frame_for_custom_view.
  2. Em onCreate:

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

    que coloca a exibição personalizada no quadro.

Neil Townsend
fonte
Isso me ajudou: "Verifique se o ID que você deseja está na exibição ou no layout que você deu para setContentView ()". O que fazer quando é uma subvisão no entanto? Tentei obter a visualização principal e, em seguida, use parentView.findById (), mas ele ainda está retornando nulo
NaturalBornCamper
@naturalborncamper se você postar uma pergunta separada com código de exemplo, eu darei uma olhada nela.
Neil Townsend
Obrigado Neil, eu já postei e alguém apontou uma maneira melhor de fazer isso, embora não esteja funcionando exatamente como deveria ser, então tive que usar uma estratégia diferente: stackoverflow.com/questions/47955376/…
NaturalBornCamper
9
    @Override
protected void onStart() {
         // use findViewById() here instead of in onCreate()
    }
Jonathan
fonte
6

Uma resposta para quem usa o ExpandableListView e se depara com essa pergunta com base no título.

Eu tive esse erro ao tentar trabalhar com TextViews em meus modos de exibição filho e grupo como parte de uma implementação ExpandableListView.

Você pode usar algo como o seguinte em suas implementações dos métodos getChildView () e getGroupView ().

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

Eu encontrei isso aqui .

Josh Metcalfe
fonte
5

Eu sou muito novo no Android / Eclipse, por engano, adicionei o material da interface do usuário ao activity_main.xmlinvés de fragment_main.xml. Levei algumas horas para descobrir isso ...

lama12345
fonte
5

FWIW, não vejo que alguém tenha resolvido isso da mesma maneira que eu precisava. Nenhuma reclamação no momento da compilação, mas eu estava obtendo uma exibição nula em tempo de execução e chamando as coisas na ordem correta. Ou seja, findViewById () após setContentView (). O problema acabou sendo que minha visão é definida em content_main.xml, mas em minha activity_main.xml, eu não tinha essa instrução:

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

Quando adicionei isso ao activity_main.xml, não mais NullPointer.

ferris
fonte
O problema de copiar e colar um fragmento é que às vezes você esquece de alterar algumas coisas ... sendo o layout correto para inflar uma delas. Obrigado!
Pablo Quemé 05/01
3

Eu tenho esse mesmo problema. Eu estava usando uma biblioteca de terceiros que permite substituir o adaptador para um GridView e especificar seu próprio layout para cada célula do GridView.

Eu finalmente percebi o que estava acontecendo. O Eclipse ainda estava usando o arquivo xml de layout da biblioteca para cada célula no GridView, mesmo que não desse indicação. No meu adaptador personalizado, ele indicava que estava usando o recurso xml do meu próprio projeto, embora em tempo de execução, não estivesse.

Então, o que fiz foi garantir que meus layouts e IDs personalizados em XML fossem diferentes daqueles que ainda estavam na biblioteca, limpando o projeto e, em seguida, ele começou a ler os layouts personalizados corretos que estavam no meu projeto.

Em resumo, tenha cuidado se estiver substituindo o adaptador de uma biblioteca de terceiros e especificando seu próprio xml de layout para o adaptador usar. Se o layout do seu projeto tiver o mesmo nome de arquivo da biblioteca, você poderá encontrar um bug realmente difícil de encontrar!

JDJ
fonte
3

No meu caso particular, eu estava tentando adicionar um rodapé a um ListView. A seguinte chamada em onCreate () estava retornando nula.

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

Alterar isso para aumentar a exibição do rodapé em vez de encontrá-lo por ID resolveu esse problema.

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

No meu caso, eu estava usando o ExpandableListView e havia definido android:transcriptMode="normal". Isso estava fazendo com que poucas crianças no grupo expansível desaparecessem e eu recebia a exceção NULL sempre que costumava rolar a lista.

Jeevan
fonte
2

Para mim, eu tinha dois layouts de XML para a mesma atividade - um no modo retrato e outro na paisagem. É claro que eu havia mudado o id de um objeto no xml landscape, mas havia me esquecido de fazer a mesma alteração na versão retrato. Certifique-se de alterar um que você faça da mesma forma para o outro xml ou você não receberá um erro até executá-lo / depurá-lo e ele não poderá encontrar o ID que não mudou. Oh erros estúpidos, por que você deve me punir assim?

ColossalChris
fonte
2

Defina o conteúdo da atividade de um recurso de layout. ie setContentView(R.layout.basicXml).;

Ajay Takur
fonte
2

Além das soluções acima, verifique se o
tools:context=".TakeMultipleImages" layout possui o mesmo valor no arquivo mainfest.xml:
android:name=".TakeMultipleImages"para o mesmo elemento de atividade. ocorre quando usar copiar e colar para criar nova atividade

user2982286
fonte
2

Eu tenho o mesmo problema, mas acho que vale a pena compartilhar com vocês. Se você precisar localizar o ViewById no layout personalizado, por exemplo:

public class MiniPlayerControllBar extends LinearLayout {
    //code
}

você não pode obter a visualização no construtor. Você deve chamar findViewById após a exibição ter sido inflada. É um método que você pode substituironFinishInflate

Shaw
fonte
2

Só queria jogar meu caso específico aqui. Pode ajudar alguém abaixo da linha.

Eu estava usando a diretiva no meu XML da interface do usuário do Android assim:

Visualização principal:

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

Visualização filho (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) sempre retornaria nulo. Mas, se eu movesse o ID da exibição filho para a tag include, ele começou a funcionar.

Pai fixo:

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

Filho fixo:

<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.
fonte
2

Meu caso não é como o anterior, nenhuma solução funcionou. Presumo que minha visão tenha sido muito profunda na hierarquia de layout. Mudei para um nível acima e não era mais nulo.

Deividas Strioga
fonte
Eu tenho o mesmo problema, um nível mais alto também pode ser encontrado .. isso é muito chato e eu gostaria de saber por que está acontecendo, pois não posso fazer meu menu como eu quero
NaturalBornCamper
Hierarquias de layout bem profundas são antipadrão, quase sempre existe uma solução mais limpa. Você está falando do menu de estouro na barra de ferramentas ou na gaveta de navegação?
Deividas Strioga
Na gaveta de navegação, eu já postei outra pergunta, na verdade, exceto que adicionar um item de menu dentro de um grupo não está funcionando, apenas o adiciona no final de todos os itens: stackoverflow.com/questions/47955376/…
NaturalBornCamper
1

No meu caso, eu havia inflado o layout, mas as visualizações filho estavam retornando nulas. Originalmente eu tinha isso:

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

No entanto, quando eu mudei para o seguinte, funcionou:

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

A chave era referenciar especificamente o layout já inflado para obter as visualizações filho. Ou seja, para adicionar footerView:

  • footerView .findViewById ...
Suragch
fonte
0

Na minha experiência, parece que isso também pode acontecer quando seu código é chamado após OnDestroyView (quando o fragmento está na pilha de trás). Se você estiver atualizando a interface do usuário na entrada de um BroadCastReceiver, verifique se esse é o caso .

Tad
fonte
0

INFLATE O LAYOUT !! (que contém o ID)

No meu caso, findViewById () retornou nulo, porque o layout no qual o elemento foi gravado não foi inflado ...

Por exemplo. fragment_layout.xml

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

findViewById (R.id.listview) retornou nulo, porque eu não havia feito inflater.inflate (R.layout.fragment_layout, ..., ...); antes disso.

Espero que esta resposta ajude alguns de vocês.

ARCA
fonte
0

Minha correção foi apenas limpar o projeto.

Liangjun
fonte
0

O findViewById também pode retornar nulo se você estiver dentro de um fragmento. Conforme descrito aqui: findViewById no fragmento

Você deve chamar getView () para retornar a vista de nível superior dentro de um fragmento. Depois, você pode encontrar os itens de layout (botões, visualizações de texto etc.)

tecnocrata
fonte
0

Eu tentei todas as opções acima, nada estava funcionando .. então tive que deixar meu ImageView estático public static ImageView texture; e texture = (ImageView) findViewById(R.id.texture_back);, então , não acho que seja uma boa abordagem, mas isso realmente funcionou para o meu caso :)

Tabish
fonte
Desculpe, eu acho visão estática é má idéia
vuhung3990
0

No meu caso, findViewById retornou nulo quando mudei a chamada de um objeto pai para um objeto adaptador instanciado pelo pai. Após tentar os truques listados aqui sem êxito, movi o findViewById de volta para o objeto pai e passei o resultado como um parâmetro durante a instanciação do objeto do adaptador. Por exemplo, eu fiz isso no objeto pai:

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

Depois passei o hdSpinner como parâmetro durante a criação do objeto do adaptador:

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

Falha para mim porque um dos campos no meu ID de atividade estava correspondendo ao ID em outra atividade. Corrigi-o, dando um ID único.

No meu loginActivity.xml, o ID do campo de senha era "password". Na minha atividade de registro, eu apenas o corrigi, fornecendo o ID r_password, e ele não retornou um objeto nulo:

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

Eu estava enfrentando um problema semelhante ao tentar fazer uma exibição personalizada para um ListView.

Eu resolvi isso simplesmente fazendo o seguinte:

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
fonte
0

Maneiras de depurar e encontrar o problema:

  • Comente todos os findViewById da sua atividade.
  • Comente tudo, exceto onCreate e setContentView
  • Execute o projeto e veja se algum layout está definido

No meu caso, eu estava usando o activity_main.xml no meu módulo de aplicativo e também no meu módulo de biblioteca. Portanto, quando eu executei as etapas acima, em vez do layout que criei na biblioteca, o layout dentro do módulo do aplicativo foi inflado.

Então, mudei o nome do arquivo activity_main.xml para activity_main_lib.xml.

Portanto, verifique se você não possui nomes de layout duplicados em todo o projeto .

Reejesh PK
fonte