findViewById () devuelve nulo para el componente personalizado en XML de diseño, no para otros componentes


91

Tengo un res/layout/main.xmlincluyendo estos elementos y otros:

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

En mi actividad onCreate, hago esto:

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

Los otros elementos se encuentran correctamente, pero foovuelven nulos. MyCustomView tiene un constructor MyCustomView(Context c, AttributeSet a)y Log.d(...)al final de ese constructor aparece con éxito en logcat justo antes del "error épico".

¿Por qué es foonulo?

Respuestas:


182

Porque en el constructor, tenía en super(context)lugar de super(context, attrs).

Tiene sentido, si no pasa los atributos, como la identificación, entonces la vista no tendrá identificación y, por lo tanto, no se podrá encontrar usando esa identificación. :-)


1
Siempre es bueno poder responder a sus propias preguntas :) Asegúrese de marcar la suya como la respuesta aceptada también.
MattC

En efecto. Lo haré cuando SO me lo permita ("Puedes aceptar tu propia respuesta en 2 días")
Chris Boyle

4
Además, no debe líneas como (MyCustomView) foo = findViewById(R.id.foo);sea MyCustomView foo = (MyCustomView) findViewById(R.id.foo);?
Jeremy Logan

3
Tuve el mismo problema, en mi caso me había olvidado el setContentView () .. XD
Tom Brito

Hay un buen ejemplo para hacer tales cosas en vogella.com: vogella.com/articles/AndroidCustomViews/article.html
Wolkenjaeger

27

Tengo el mismo problema porque en mi vista personalizada anulé el constructor pero invoqué el supercontructor sin attrs paramete. Eso es copiar y pegar)

Mi versión anterior del constructor:

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

Ahora tengo:

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

¡Y eso funciona!


El mismo problema aquí. Por cierto, también fue un error de copiar y pegar para mí.
KurtCobain

A mi me pasó lo mismo. La respuesta más correcta en Stackoverflow. Cuando agregue AttributeSet attrs, todo está bien.
spikeyang

Supongo que todos buscamos el mismo tutorial con vista personalizada;) este error me llevó 0,5 h de depuración inútil ...
KrwawyKefir

¡Esto funcionó para mí también! Luché contra esto durante bastante tiempo. ¡Gracias!
us_david

18

Yo tuve el mismo problema. Mi error fue ese: escribí

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

y como utilicé un inflador para "cargar" la vista desde un archivo XML, la última línea estaba mal. Para solucionarlo, tuve que escribir:

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

Escribí mi solución, en caso de que alguien tenga el mismo problema.


Amigo, eres un genio. Esa fue la única solución que funcionó para mí de todas las numerosas que leí en SO
IgorGanapolsky

Este también fue el problema para mí. Vaya, qué pedazo de ... Me hubiera llevado días resolver esto por mi cuenta. ¡Gracias!
poshaughnessy

18

Parece que hay varias razones. Acabo de usar "Limpiar ..." en Eclipse para resolver un problema similar. (FindViewByID había funcionado antes y por alguna razón comenzó a devolver nulo).


1
aparentemente, el problema subyacente es que los ID de R.java de alguna manera se rompen o tal vez no se actualizan. He notado esto no solo con los ID, sino también en otros casos, por ejemplo, una cadena incorrecta mostrada en un TextView, etc. Sin embargo, no sé realmente por qué sucede esto.
medusa

Esto me estaba causando dolor durante demasiado tiempo; una limpieza realmente me lo arregló.
Nicholas MT Elliott

1
Limpieza, de hecho. ¡Vaya, eso apesta!
Tim Büthe

11

Mismo problema, pero solución diferente: no llamé

setContentView(R.layout.main)

ANTES de que intenté encontrar la vista como se indica aquí


Creo que esta es la solución si obtiene un elemento en otra vista en lugar de la vista relacionada actual.
StarCub

4

Si tiene varias versiones de diseño (dependiendo de las densidades de pantalla, versiones del SDK) asegúrese de que todas incluyan el elemento que está buscando.


2

En mi caso, findViewById devolvía nulo porque mi vista personalizada se veía así en el XML principal:

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

y descubrí que cuando agregué las cosas xmlns funcionó así:

        <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

Asegúrese de que la setContentView(R.layout.main)declaración llame antes de la findViewById(...)declaración;


1

Para mí, el problema se resolvió cuando agregué la carpeta res a la Fuente en Java Build Path en la Configuración del proyecto.


1

Me encontré con el mismo problema hace un tiempo cuando agregué una Vista personalizada a través del XML de diseño y luego intenté adjuntar una devolución de llamada en otro lugar de la aplicación ...

Creé una vista personalizada y la agregué a mi "layout_main.xml"

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

Y en la actividad principal, quería adjuntar algunas devoluciones de llamada y obtener referencias a los elementos de la interfaz de usuario del XML.

public class MainActivity extends Activity {

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

        // ...

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

El iniciador no estaba haciendo nada elegante, pero los cambios que intentó realizar en la vista personalizada (MUIComponent) u otros elementos de la interfaz de usuario no personalizados simplemente no aparecían en la aplicación.

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
        // ...
    }

}

La diferencia entre "badInst" y "goodInst" es:

  • badInst usa el findViewByID de la actividad
  • goodInst infla el diseño y usa el diseño inflado para realizar la búsqueda

Noté que Vincent tiene la misma solución ... y su respuesta es más corta ... +1 en su lugar :)
DevByStarlight

1

Esto me sucedió con un componente personalizado para Wear, pero es un consejo genérico. Si está usando un Stub (como el que estaba usando yo WatchViewStub), no puede simplemente poner la llamada en findViewById()cualquier lugar. Todo lo que hay dentro del talón debe inflarse primero, lo que no sucede solo después setContentView(). Por lo tanto, debe escribir algo como esto para esperar a que eso suceda:

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

Mi problema fue un error tipográfico. Había escrito android.id(punto) en lugar de android:id. :PAGS

Aparentemente, no hay verificación de sintaxis dentro de mi componente personalizado xml. :(


0

Tuvo el mismo problema.

Tuve diseño con pocos niños. Desde el constructor de uno de ellos, estaba tratando de obtener una referencia (utilizando context.findViewById) a otro niño. No funcionó porque el segundo hijo se definió más en el diseño.

Lo resolví así:

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

Funcionaría también si el orden de los niños fuera opuesto, pero supongo que, en general, debería hacerse como el anterior.


1
En general, no debería usar findViewByIden el constructor de a View, sino poner el código de inicialización en OnFinishInflate?
Sanjay Manohar

0

El findViewById()método a veces regresa nullcuando la raíz del diseño no tiene android:idatributo. El asistente de Eclipse para generar un archivo xml de diseño no genera automáticamente un android:idatributo para el elemento raíz.


0

En mi caso, la vista estaba en el padre, NO en la vista en la que estaba tratando de llamarla. Entonces, en la vista secundaria, tuve que llamar:

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

0

La opción 'limpia' funcionó para mí.

En mi caso, la causa principal es que el código fuente reside en un recurso compartido de red, y mi estación de trabajo y mi servidor de archivos no se sincronizaron correctamente y se desviaron 5 segundos. Las marcas de tiempo de los archivos creados por Eclipse están en el pasado (porque son asignados por el servidor de archivos) con el reloj de la estación de trabajo, lo que hace que Eclipse resuelva las dependencias entre los archivos generados y de origen incorrectamente. En este caso, una 'limpieza' parece funcionar, porque fuerza una reconstrucción completa en lugar de una construcción incremental que depende de marcas de tiempo incorrectas.

Una vez que arreglé la configuración de NTP en mi estación de trabajo, el problema nunca volvió a ocurrir. Sin la configuración adecuada de NTP, sucedería cada pocas horas, ya que los relojes se mueven rápidamente.


Debería agregar esto al comentario de la respuesta anterior
Trung Nguyen

0

Para agregar otro error trivial a las respuestas a tener en cuenta:

Compruebe que está editando el archivo XML de diseño correcto ...


0

Tuve el mismo problema porque olvidé actualizar la identificación de la vista en todas mis carpetas de diseño.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.