inflate() en Android – Inflar y adjuntar Views


Cuanta importancia y que de misterio rodean al método inflate(), que pertenece al objeto de la clase LayoutInflater. Método que se utiliza para construir y añadir las Views a los diseños de:

  • Fragment
  • Menu o ActionBar
  • Adapter
  • Dialogs
  • Para añadir una View a otra en cuando precisemos
  • Entre otros muchos casos
  • ¿Y Activity no lo utiliza? Claro que lo usa, pero Android nos lo facilita de otra manera. En vez del método inflate() -que es un inflado implícito- lo han llamado setContentView() -en un inflado explícito.

Suficiente argumento que hacen a este método de los más importantes en Android, por lo que requiere un artículo dedicado.

Antes de empezar, después de mucho tiempo buscando una explicación clara que parece no existir por ningún lado o un consenso de qué es lo que realmente hace el método inflate(), he de indicar que esta explicación es mi visión (después de años trabajando con ello, de haber investigado y deducido una explicación razonable). No es por criticar, pero casi ni los propios de Google parece que sepan lo que hace; debido a la falta de explicaciones en la documentación, y de darlo por dado o con una pobre descripción en las apariciones de las que tengo constancia. Sin embargo, aquí lo voy a explicar con detalle después de mucho trabajo de investigación y deducción. Ahora sí, comencemos.

Una cosa que hay que tener muy clara del método inflate() es –lo que lleva demasiado a confusión- que inflar NO se refiere a insertar unas Views en un ViewGroup, sino a poner los atributos de diseño del que podría ser el ViewGroup padre. Aquí seguramente surja la duda ¿Pero si cuando inflo se añaden las Views al ViewGroup? Y es que inflate() aparte de inflar, también tiene la opción de adjuntar (adjuntar es un valor añadido a la función inflate(), pero para nada adjuntar se refiere a inflar).

Aclarémoslo en un ejemplo, en el que vamos a tener la siguiente estructura de carpetas (el código de este ejemplo es un proyecto completo funcional, puedes crear un nuevo proyecto probarlo):

Estructura proyecto Inflate de Android - www.jarroba.com

Supongamos que tenemos un diseño que dibuja un texto como el siguiente diseño (Aquí no pondré capturas de pantalla del emulador de Android, sino abstracciones de lo que el usuario verá, con motivo de poder tomar lo importante de las imágenes):

Layout Abstracto para Ejemplo Infalte Android 1 - www.jarroba

Su fichero de diseño correspondiente en res/layout/adjuntar_en_un_viewgroup.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical" >

	<TextView
	android:id="@+id/textView1"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="@string/otro_fichero_de_dise_o_xml"
	android:textAppearance="?android:attr/textAppearanceLarge" />

</LinearLayout>

Y lo que queremos es adjuntar el diseño anterior al RelativeLayout de este otro diseño:

Layout Abstracto para Ejemplo Infalte Android 2 - www.jarroba

Con el fichero res/layout/fichero_de_disenio.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
 
	<Button
	android:id="@+id/button1"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:layout_gravity="center"
	android:text="@string/otra_view" />

	<RelativeLayout
	android:id="@+id/RelativeLayout_contenedor"
	android:layout_width="100dp"
	android:layout_height="100dp"
	android:layout_gravity="center"
	android:orientation="vertical" >
	</RelativeLayout>

</LinearLayout>

Como queremos es que la estructura del primer diseño se adjunte al ViewGroup del segundo diseño (se puede decir que es algo parecido a lo que se hace con las Views Merge e Include, pero en dinámico, desde Java). Para ello obtendremos el LayoutInflater del Context de la Activity y utilizaremos su método inflate() de esta manera:

public class MainActivity extends Activity {

	@Override
	protectedvoid onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.fichero_de_disenio);

		RelativeLayout contenedor = (RelativeLayout) findViewById(R.id.RelativeLayout_contenedor);

		LayoutInflater inflater = LayoutInflater.from(this);

		View laViewInflada = inflater.inflate(R.layout.adjuntar_en_un_viewgroup, contenedor, true);
	}

}

Llegó el momento de tener muy clara la diferencia entre inflar y adjuntar:

Inflar

Por contra a la intuición, NO infla al ViewGroup contenedor con las Views que le pasamos (el fichero de diseño XML que queremos adjuntar al contenedor). Lo que se infla es la nueva jerarquía de Views (el diseño) que les pasamos con los atributos de diseño del padre (con los atributos del ViewGroup contenedor). Es decir, le decimos a las nuevas Views el tamaño que tienen que tener para que quepan en el padre, la gravedad, entre otros (dependerán del ViewGroup que usemos para inflar: LinearLayout, FrameLayout, Fragment, etc). Es por lo que se deduce que no dibuje en pantalla lo inflado y por tanto no pueda recibir eventos.

Inflar Views con Inflate de Android - www.jarroba.com

En el ejemplo, le pasaríamos al método inflate() el fichero de diseño de “adjuntar_en_un_viewgroup.xml” y el RelativeLayout del que será el contenedor (fíjate en los parámetros primero y segundo que se le pasa al método inflate() ). De este modo, se infla la estructura de views del fichero con los parámetros del contenedor que se le pasan del que será el padre y contenedor.

Adjuntar

Añade el nuevo diseño que se infló a la ViewGroup y ahora sí lo muestra en pantalla y podrá recibir eventos. El tercer parámetro del método inflate() indica si queremos que lo adjunte inmediatamente o no (por ejemplo, en Fragment no interesa, pues lo hará el propio Fragment en otro momento, por eso lo retornamos el objeto LayoutInflater en el método onCreteView() ).

Adjuntar Views con Inflate de Android - www.jarroba

Volviendo al ejemplo. El tercer parámetro del método inflate() indica si queremos que la estructura que antes hinchamos se adjunte al contenedor (true) o no (false).

Por lo que después de adjuntar (que no de inflar), a nivel interno nos habrá generado la siguiente estructura de diseño que el usuario podrá ver y responderá a eventos:

Layout Abstracto para Ejemplo Infalte Android 3 - www.jarroba

Aunque no se ve, a nivel interno Android realizará la siguiente estructura de diseño XML:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

	<Button
	android:id="@+id/button1"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:layout_gravity="center"
	android:text="@string/otra_view" />

	<RelativeLayout
	android:id="@+id/RelativeLayout1"
	android:layout_width="100dp"
	android:layout_height="100dp"
	android:layout_gravity="center"
	android:orientation="vertical" >

		<LinearLayout
		android:id="@+id/LinearLayout1"
		android:layout_width="match_parent"
		android:layout_height="match_parent"
		android:gravity="center"
		android:orientation="vertical" >

			<TextView
			android:id="@+id/textView1"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:text="@string/otro_fichero_de_dise_o_xml"
			android:textAppearance="?android:attr/textAppearanceLarge" />

		</LinearLayout>

	</RelativeLayout>

</LinearLayout>

 

Parámetros de Inflate()

Ya los hemos visto como funciona. Ahora definimos los tres parámetros que solicita el método inflate() (hay otras sobrecargas de este método, pero explicamos el de tres parámetros que se suele utilizar más y es el que se recomienda):

  1. Recurso de diseño (resource): La referencia de R del diseño que queramos inflar.
  2. Contenedor raíz (root de tipo ViewGroup): El contenedor cuyos parámetros de su diseño (todos sus “android:layout_xxxxx”) inflarán al anterior recurso de diseño indicado en el parámetro anterior. Y si el tercer parámetro lo permite con un true, se adjuntará el diseño anterior a este contenedor. Puede interesar pasar aquí un “null” si no queremos que se infle con ningún parámetro de ningún padre.
  3. Si adjuntar al contenedor que será la raíz (boolean): Si es “true” indica si el diseño (primer parámetro) que es inflado por el ViewGroup contenedor (segundo parámetro) debe, además, adjuntar su jerarquía de Views a este contenedor. A veces interesa poner este parámetro a “false” porque nos interese solo inflar, debido a que se adjuntará lo inflado en otro momento diferente posterior (por eso devuelve una View inflada el método inflate() ); el motivo suele ser que no se cree dos veces el mismo conjunto de Views (Como en el método onCreateView() de Fragment, donde se encarga el Fragment de adjuntarlo cuando deba; si lo ponemos a “true” nos aparecerá dos veces lo mismo)

 

Algunos sitios más donde utilizar inflate()

Hemos visto en el anterior ejemplo como aplicar inflate() directamente sobre una ViewGroup en cualquier momento. Ahora veamos unos ejemplos más:

Fragment

Lo utilizamos en la parte del ciclo de vida onCreateView() del Fragment. Este mismo método nos facilita un objeto de tipo LayoutInflater que podemos usar y el ViewGroup donde debe encajar. El inflate() nos devolverá la View que debemos retornar (Caso de uso completo y ejemplo en el artículo sobre Fragments).

public class MiFragment extends Fragment {

	public MiFragment() {
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		View rootView = inflater.inflate(R.layout.adjuntar_en_un_viewgroup, container, false);

		return rootView;
	}
}

 

Dialog

De manera parecida los cuadros emergentes de diálogo también usan este método inflate(). Aquí podemos obtener el objeto de tipo LayoutInflater desde el mismo Context de la Activity que lo vaya a incorporar.

public class MiCuadroDeDialogo extends DialogFragment {
	@Override
	public Dialog onCreateDialog(Bundle savedInstanceState) {
		AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

		View v = getActivity().getLayoutInflater().inflate(R.layout.mi_layout, null);
		builder.setView(v);

		return builder.create();
	}
}

 

Menu o ActionBar

Aquí se emplea en el método onCreateOptionsMenu() para llenar de opciones el Menu o el ActionBar.

public class MainActivity extends Activity {

	@Override
	protected void onCreate(BundlesavedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}
 
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.elementos_menu_adjuntar_en_un_viewgroup,  menu);
		return true;
	}

}

 

Adapter

Para un adaptador podremos obtener el LayoutInflater del servicio del sistema y luego utilizar inflate() (Tienes un ejemplo completo en el artículo sobre listados):

public class MiAdaptador extends BaseAdapter{

	private ArrayList<?> entradas;
	private Context contexto;

	public Lista_adaptador(Context contexto, ArrayList<?> entradas){
		super();
		this.contexto = contexto;
		this.entradas = entradas;
	}

	@Override
	public
	View getView(int posicion,View view,ViewGroup pariente){
		if(view == null){
			LayoutInflater vi =(LayoutInflater) contexto.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			view = vi.inflate(R.layout.adjuntar_en_un_viewgroup, null);
		}
		return view;
	}

	@Override
	public int getCount(){
		return entradas.size();
	}

	@Override
	public Object getItem(int posicion){
		return entradas.get(posicion);
	}

	@Override
	public long getItemId(int posicion){
		return posicion;
	}
}

  Puede que me haya explayado un poco. Es necesario entender este concepto para no copiar y pegar código sin saber qué hace. Además, este método seguro que lo utilizarás en más de una ocasión 🙂  

Bibliografía:

Como indiqué al principio del artículo, debido a la poca información existente sobre el tema, casi todo es de experiencia, recopilación y creación personal. No puedo quitar el prestigio y la merecida mención en las webs donde me inspiré:

Comparte esta entrada en:
Safe Creative #1401310112503
inflate() en Android – Inflar y adjuntar Views por "www.jarroba.com" esta bajo una licencia Creative Commons
Reconocimiento-NoComercial-CompartirIgual 3.0 Unported License.
Creado a partir de la obra en www.jarroba.com

31 thoughts on “inflate() en Android – Inflar y adjuntar Views”

  1. Hola Ramón!. Muchas gracias por el artículo, me animo de a decir que me resultó esclarecedor. Pero como Albert decía que «uno entiende algo cuando es capaz de explicarlo con sus propias palabras», querría dejarte mi definición con mis propias palabras para que si puedes las evalúes y me digas si es correcta.

    Inflar significa modificar o adaptar el diseño de un layout según los parámetros de diseño de otro layout (el padre). Luego, ese diseño modificado se puede adjuntar, o no. Como resultado obtendremos un objeto View, el cual podremos manipular.

    Si está bien, quería de paso hacerte otra pregunta. ¿Importa el context que le pasemos?. Quiero decir, en general le vamos a pasar el context del activity en donde estemos trabajando, pero es una duda más bien teórica.

    Saludos y muchas gracias!

  2. Hola, Ramón.
    ¿Podrías informarme sobre cómo obtener una referencia (id distintivo) de cada uno de los textview que se hayan añadido dinámicamente mediante el método inflate?
    Usando el método getId() del objeto view recibido por el método onTouch(View v, MotionEvent event) siempre se obtiene el Id del textview fuente.
    Gracias

  3. Hola, tengo un problema con mis vistas. Tengo una actividad la cual tiene una vista de este tipo: (un relativeLayout dentro de otro)

    conten_home.xml:
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android&quot;
    xmlns:app="http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools="http://schemas.android.com/tools&quot;
    android:id="@+id/contenedorHomePrincipal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#ffffff"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="x.HomeActivity"
    tools:showIn="@layout/app_bar_home">
    <RelativeLayout
    android:id="@+id/contenedorHome"
    android:orientation="vertical"
    android:layout_alignParentTop="true"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    </RelativeLayout>

    </RelativeLayout>

     

    El relativeLayout interior (id=contenedorHome), es el que alberga cada fragmento que voy creando dinamicamente

    El problema viene de que a esta vista le quiero añadir mas de un fragmento a la vez. Se me ha ocurrido crear una nueva vista del tipo RelativeLayout padre, y a su vez crear nuevos RelativeLayout hijos con las caracteristicas oportunas para formar la vista deseada. Estos RelativeLAyout seran cada uno de los fragmentos desados. (fragment_all_avatar.xml

    Para ello adjunto a la vista como explicas en esa web:

    contenedor = (RelativeLayout) findViewById(R.id.contenedorHomePrincipal);//conten_home.xml
    inflater = LayoutInflater.from(this);
    inflatedView = inflater.inflate(R.layout.fragment_all_avatar, contenedor, true);

    //Aqui, añado los fragmentos a la vista de los fragmentos
    RelativeLayout contenedor_cara_3D = (RelativeLayout) inflatedView.findViewById(R.id.layout_cara_3D);
    RelativeLayout contenedor_cara_flexion = (RelativeLayout) inflatedView.findViewById(R.id.layout_cara_flexion);

    fragmentTransaction.add(contenedor_cara_3D.getId(),cara_fragment_3D,"avatar3D");
    fragmentTransaction.add(contenedor_cara_flexion.getId(),caraFlexionFragment,"cara_flexion");

    AllAvatarFragment all_fragments_avatar = new AllAvatarFragment();
    fragmentTransaction.replace(R.id.contenedorHome, all_fragments_avatar ,"fragment_all_avatar");
    fragmentTransaction.addToBackStack(null);
    fragmentTransaction.commit();

    Hasta aquí todo bien, sustituye el framento anterior por todo el fragmento de framentos, pero pierdo al volver atrás o intentar cambiar a otro de los framentos anteriores, la actividad se queda en blanco.

    Lo curioso es que si solo añado un fragmento , o cambio el relativeLayout por otro tipo como Framelayout o LinearLayout en fragment_all_avatar, si funciona y no devuelve las vistas en blanco, pero pierdo la orientación que quiero de la otra vista.

     

    ¿Hay alguna forma de evitar esto????, si alguien me lee ayuda please.

     

    1. Puedes poner varios Fragments, que se quede en blanco será por el ciclo de vida al pulsar el botón de volver atrás, hay maneras de modificar el comportamiento (desde la Activity o desde el AndroidManifest). En nuestro libro gratuito de Android http://jarroba.com/libro-android-100-gratis tienes ejemplos para poner varios Fragments y como funciona el ciclo de vida con la vuelta atrás. También tienes ejemplos en http://jarroba.com/programar-fragments-fragmentos-en-android/ y en https://developer.android.com/guide/components/fragments.html

  4. Hola Ramón. Espero que me puedas ayudar con estas dudas.

    Ante todo gracias porque estoy llevando un curso de Android y tu libro Android 100% me está ayudando a complementar muchas cosas. Por otro lado, en mi curso he visto un ejemplo de adaptador para un RecyclerView. Tengo un layout de cardview donde está definida una imagen con un texto y aparte mi layout principal. Asimismo, tengo una clase Adaptador con una clase anidada static ViewHolder (cada uno con sus respectivas herencias). En la clase Adaptador tengo los métodos onCreateViewHolder(ViewGroup parent, int ViewType) , onBindViewHolder(ViewHolder holder, int position), getItemCount() y su constructor que recibe un ArrayList. Quisiera saber lo siguiente:

    1) onCreateViewHolder se encarga de "inflar" el layout donde está mi layout cardview de acuerdo a los parámetros del layout principal (por medio de el parámetro parent)?

    2) Cómo puede el Adaptador recibir los parámetros del padre (o layout principal) si lo único que le paso al constructor es un ArrayList?

    3) Tengo esto dentro del método ViewHolder onCreateViewHolder (ViewGroup parent, int ViewType)

    //tengo el inflate:

    { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview, parent, false); 

    //Luego esta variable v se devuelve como parámetro del ViewHolder:

    return new ViewHolder (v); }

    //en el LayoutInflater está marcado como "false" el último parámetro. Entonces debo suponer que la variable v contiene una instancia View del layout cardview (debidamente adaptada a su parent)?. Y si fuera "true" entonces v contendría una instancia de los dos layouts juntos?

     

    4) Qué es lo que devuelve exactamente el método .inflate()? Es una instancia de un View para que pueda ser controlado y sus métodos usados? (Algo comparable a un " View instanciaDelLayout = new View (layout.xml) " ?

    5) En el ejemplo que tengo, ese último parámetro es false y aún así se muestra correctamente (el layout principal con sus tarjetas y dentro de sus tarjetas sus elementos). ¿A qué se debe eso? en el código no se añade manualmente con un AddView() o algo parecido. ¿Quién lo añade al principal entonces si es que no lo hace el inflate() ?

    5) Tengo lo siguiente en el código del ViewHolder extends RecyclerView.ViewHolder 

    { public ViewHolder (View itemView) { private ImageView miImagen; private TextView miTexto;

    super(itemView);

    miImagen = (ImageView) itemView.findViewById(R…..));

    miTexto = (TextView) itemView.findViewById(R…..));

    }}

    //Y dentro del método onBindViewHolder(ViewHolder holder, int position)

    {

    ClaseArray array = miArrayList.get(position);

    holder.ImgFoto.setImageResource(array.getFoto());

    holder.TvTexto.setText(array.getNombre());

    }

    //Entonces, el orden es el siguiente: PRIMERO: onCreateViewHolder toma el layout cardview, lo acomoda a su padre, lo junta y envía una instancia a ViewHolder. SEGUNDO: la clase static ViewHolder ASOCIA el View recibido (la instancia de los dos layout juntos) con sus elementos contenidos. Crea instancias de TextView, ImageView, etc. TERCERO: Finalmente onBindViewHolder los "sincroniza" con sus respectivos valores (textos, imágenes, etc). Está bien mi análisis?

     

    6) Finalmente, cómo se realiza el inflado del layout cuando se usa el método (automático) setContentView dentro de onCreate? Se supone que cuando ASOCIAMOS instancias de TextView, ImageView, etc y luego les asignamos sus valores estamos haciendo lo mismo que el ViewHolder y el onBindViewHolder?

     

    Espero que me puedas ayudar a aclarar esas dudas por favor. Estoy practicando para ser un buen desarrollador Adnroid y quiero alguna vez poder saber tantas cosas sobre programación como tú. De antemano muchas gracias!

     

  5. hola, hay alguna manera de que dos o mas layouts esten asociados a un mismo fragment? Lo que intento hacer es tener un fragment en donde

    se muestre una lista (a un lado de la pantalla) y en otro fragment (el resto de la pantalla) muestre un layout pero el diseño de este layouts es distintno a los demás entonces no puedo generalizar con una sola estructura. Por eso mi pregunta es si hay alguna forma de asociar dos o mas layouts a un mismo fragment. Agradecería si alguien me puede ayudar. Gracias.

    1. Se puede realizar inyecciónes de Layouts para crear estructuras dinámicas sin problemas por ejemplo en un LinearLayout utilizar el método addView() para añadir la View que necesites (que puedes encontrar en los recursos con findViewById() )

  6. acabo de realizar estos pasos referentes a lo que mencionas (mi proyecto consta de un spinner, y al seleccionar una opcion quisiera que mostrara el fichero inflado, pero no lo hace).. He seguido los pasos que mencionaste; pero aun sin exito a que se debe?

    1. Para Spinner no hace falta que infles pues hay otros métodos que lo hacen por tí. Inflar es para ciertas cosas concretas y para entender su funcionamiento. Echa un vistazo a los ejemplos en http://developer.android.com/intl/es/guide/topics/ui/controls/spinner.html también tienes un ejemplo de Spinner complejo en http://jarroba.com/expansion-listview/

  7. Hola compañero,

    ¿sabeís como poner una imagen en función de la coordenada que clikea el usuario??

    gracias

    1. Hola Gonzalo. Es sencillo, solo tienes que escuchar el evento de tocado (touch) de pantalla (ejemplo en http://developer.android.com/intl/es/training/graphics/opengl/touch.html), recoger las coordenadas y recolocar la View de la imagen dentro de su ViewGroup (como en un RelativeLayaut http://developer.android.com/intl/es/guide/topics/ui/layout/relative.html).

      También puedes utilizar el drag and drop http://developer.android.com/intl/es/guide/topics/ui/drag-drop.html

  8. Hola Ramón, muchas gracias por este post, esta muy completo.

    Fijate que soy nuevo en Android y tengo esta duda. Necesito hacer una especie de blog desplegable en una ScrollView. Esta vista debe contener las publicaciones que puede ver ese usuario. Mi duda es si puedo usar inflate para adjuntar todas publicaciones que puede ver el usuario en forma de vistas, o si tengo que usar algun otro objeto.

    Gracias por tus comentarios.

  9. Hola, primero que nada gracias por tomarte tu tiempo para dar una exlplicación sobre Infate(). Segundo, traté de seguuir tu ejemplo y me quedó claro la primera parte. El problema viene cuando ya tienes la vista infalda. Es decir, después de la instrucción:

    View laViewInflada = inflater.inflate(R.layout.adjuntar_en_un_viewgroup, contenedor, true);

    en este caso Eclipse me marca como Unused, es decir ya se tiene la vista pero no se usa. ¿Cómo hago para que se cree el resultado que incluya esta vista?. 
    Gracias por tus comentarios. 

    1. Hola Alberto. En el ejemplo puse la variable «laViewInflada» para saber enseñar que es lo que devuelve y para poder utilizarse si fuera necesario (Por ejemplo, puedes utilizar esa variable para encontrar algún elemento de la View con findViewById() ). Pero efectivamente no se usa esa variable .

  10. Hoy he tenido una discusión con un comañero.

    Yo soy de la opinión que si en una misma Activity dos Fragments inflan cada uno en su OnCreate la View principal (y la devuelven en el parametro de salida), y una ListView dentro del mismo Layout que previamente se ha inflado, cada uno de los Fragments tienen una instancia distinta (con distinta referencia) tanto de la View como de la ListView.

    Mi compañero dice que no, y que desde ambos Fragments se está trabajando con los mismos objetos. Hemos creado un proyecto de prueba, que lógicamente no ha funcionado, cuando un Fragment «actualiza la ListView común» habiendo hecho cada Fragment su propio inflado. Aún así no lo he logrado convencer.

    Podríais aportar una explicación sobre que ocurre en la situación que os he comentado? (A ver si asi se queda ya tranquilo el hombre)

    Muchas gracias.

    1. Hola Manu,

      Siempre hay que escuchar todas las opiniones, pues otra perspectiva nos da siempre nueva información en la que no hemos pensado 🙂

      Te cuento. Cada Fragment es un objeto que instancia Android por separado (pues son clases Java de toda la vida). Cuando se produce el inflado de un Fragment, lo que Android hace es copiar los datos a la jerarquía de Views al nuevo diseño y luego realizar el adjuntado. Hay que tener en cuenta que podemos utilizar varios Fragments con el mismo layout (al igual que podemos instanciar varias veces una clase en diferentes objetos), y cada Fragment podría tener un comportamiento diferente (es todo igual, como en los listados, que cada fila tiene repetido el diseño y cada fila con un comportamiento diferente, un ejemplo en http://jarroba.com/listview-o-listado-en-android/).
      Para que dos Fragments diferentes (tengan o no el mismo diseño) compartan información hay que realizar por ejemplo el callback (echa un vistazo en http://jarroba.com/programar-fragments-fragmentos-en-android/) o mandar la información de alguna manera (base de datos, almacenamiento local, patrón singleton, …), y luego, claro, cargar la información. Tenéis fuentes de información en: http://developer.android.com/guide/components/fragments.html y en http://developer.android.com/reference/android/app/Fragment.html

      Espero que sirva para aclarar ideas. Ahora solo queda seguir avanzando 😀

  11. Ahh ya entiendo yo pensaba que el inflate llamaba el diseño y este la activity, con el intent funciona, pero el problema es que quiero mostrar una activity con su diseño y sobre esta otra activity con su diseño, no 2 activities cada una en la mitad de la pantalla sino las 2 una encima de otra, jejeje no se si entiendes.

      1. 😀 gracias Ramón voy a empezar a entender Fragments, una ultima duda mi proyecto original era hacer que la camara se vea en tiempo real (surface) y q en unos textbox se vean los datos del acelerometro(activity 2), por eso necesitaba q la activity de los datos del sensor se vea sobre la camara de manera transparente, eso sera posible hacer con los Fragments ?.
        De nuevo te agradezco por tu ayuda, eres un excelente profesional.

  12. Hola, que excelente paguina, tengo una duda aunque creo se aparta un poco de este caso, tengo 2 clases y 2 layouts, mediante el addcontent view muestro el layout 2 sobre el 1 pero al llamar al metodo de calculos me dice que no encuentra el metodo.

    1. Buenas Carlos,

      me faltaría el log del error pero creo que cuando dices addcontent te refieres a setContentView(). Por como dices que tienes clases entiendo que no los has extendido de Activity, de ahí que no encuentre al método pues son de Activity.

      Mira a ver; sino defíneme un poco más la estructura del proyecto y cópiame el log con el error 😉

      1. Hola Ramón, muchas gracias por tu atencion y por tu tiempo 😀

        Este es parte del codigo
        public class ConvertidorActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.convertidor_activity);
        etDolares = (EditText)findViewById(R.id.etDolares);
        tvDolares = (TextView)findViewById(R.id.Dolares);
        tvRespuesta = (TextView)findViewById(R.id.tvRespuesta);

        LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.calculadora_activity, null);
        this.addContentView(view, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
        }

        public void convertir (View v){
        tvEuros.setText(«El valor en dolares es » + Double.parseDouble(etDolares.getText().toString()) * 2);
        }
        //Segunda clase
        public class CalculadoraActivity extends Activity{
        @Override
        protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.calculadora_activity);
        etNum1 = (EditText)findViewById(R.id.etNum1);
        tvRespuesta = (TextView)findViewById(R.id.tvRespuesta);
        btnRespuesta = (Button)findViewById(R.id.btnRespuesta);
        }
        public void calcular(View v){
        tvRespuesta.setText(«La suma es: «+Double.parseDouble(etNum1.getText().toString()) * 5);
        }
        //Segundo xml (este se despliega sobre el otro)
        android:onClick=»calcular»

        El error es que no encuentra el metodo calcular de la clase Calculadora
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): FATAL EXCEPTION: main
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): java.lang.IllegalStateException: Could not find a method calcular(View) in the activity class com.android.conertidor.ConvertidorActivity for onClick handler on view class android.widget.Button with id ‘btnRespuesta’
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at android.view.View$1.onClick(View.java:2131)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at android.view.View.performClick(View.java:2485)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at android.view.View$PerformClick.run(View.java:9080)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at android.os.Handler.handleCallback(Handler.java:587)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at android.os.Handler.dispatchMessage(Handler.java:92)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at android.os.Looper.loop(Looper.java:123)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at android.app.ActivityThread.main(ActivityThread.java:3683)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at java.lang.reflect.Method.invokeNative(Native Method)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at java.lang.reflect.Method.invoke(Method.java:507)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at dalvik.system.NativeStart.main(Native Method)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): Caused by: java.lang.NoSuchMethodException: calcular
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at java.lang.ClassCache.findMethodByName(ClassCache.java:247)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at java.lang.Class.getMethod(Class.java:962)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): at android.view.View$1.onClick(View.java:2124)
        05-21 21:34:17.459: ERROR/AndroidRuntime(347): … 11 more

        1. Estás utilizando la propiedad android:onClick del Button para llamar directamente, para ello siempre ha de existir este método cuando lo cargues en la Activity (Tenemos un ejemplo de como hacerlo aquí http://jarroba.com/activity-entender-y-usar-una-actividad/). Fíjate si el botón que ejecuta el método calcular() efectivamente esté en el fichero de diseño calculadora_activity.xml. De cualquier modo ya no recomiendo utilizar la propiedad android:onClick desde que salieron los Fragments. Es mejor que uses un evento listener normal o una implementación callback de onClick. Para el evento normal puedes hacerlo así:

          Button bCalcular = (Button) findViewById(R.id.Button_Calcular);
          bCalcular.setOnClickListener(new OnClickListener() {
          @Override
          public void onClick(View v) {
          // el contenido del método calcular()
          }
          });

          1. Hola Carlos, gracias por tu apoyo y por tu valioso tiempo, hice lo que me recomendaste pero el error es casi el mismo:
            ERROR/AndroidRuntime(479): java.lang.IllegalStateException: Could not find a method calcular(View) in the activity class com.android.conertidor.ConvertidorActivity for onClick handler on view class android.widget.Button with id ‘btnRespuesta’
            ERROR/AndroidRuntime(479): Caused by: java.lang.NoSuchMethodException: calcular

            Hice una pequeña prueba, llamando con un boton a toda la actividad Calcular y funciona perfectamente, el problema es cuando quiero q se muestre sobre la actividad principal.
            btnRespuesta.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
            tvRespuesta.setText(«La suma es: «+Double.parseDouble(etNum1.getText().toString()) * 5);
            }
            });
            }

          2. ¡Ojo! Que lo que te ocurre es que cargas el fichero de diseño calculadora_activity.xml solo (inflate() solo sirve para inflar y adjuntar un diseño), no la Activity CalculadoraActivity.java.

            Supongo que quieres abrir la Activity por lo que sustituye este código:
            LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View view = inflater.inflate(R.layout.calculadora_activity, null);
            this.addContentView(view, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

            Por este otro y me cuentas:
            Intent intent = new Intent(this, CalculadoraActivity.class);
            startActivity(intent);

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies

ACEPTAR
Aviso de cookies