Comunicando Fragments con Java
En este tutorial aprenderemos los conceptos necesarios para comunicar fragments en un mismo activity. Al finalizar este tutorial podremos crear una aplicación de una única pantalla con dos fragments por los que enviaremos información. Comenzaremos a ver algunos conceptos un poquito más fuertes así que ten lista una buena taza de café.
Índice
1. Código dentro del Fragment
Cuando creemos un Fragment usando Fragment(Blank) tendremos código autogenerado en el archivo java del fragment. Este código es parte de un método para crear instancias de nuestro Fragmente usando el patrón Factory. Usamos este método si necesitamos enviar algún parámetro a nuestro fragment desde el activity. Limpiando el código autogenerado obtendríamos lo siguiente que explicaremos a continuación.
public class PrimerFragment extends Fragment {
// Los parametros que se enviaran
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// La variable que obtendrán los paramtros
private String mParam1;
private String mParam2;
// Constructor del fragment
public PrimerFragment() {
// Required empty public constructor
}
// Llamaremos a este onstructor para pasar parametros al fragment
public static PrimerFragment newInstance(String param1, String param2) {
PrimerFragment fragment = new PrimerFragment();
// Bundle es un objeto usado para transportar parametros
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
// onCreate sucede antes de crear la vista, por lo que aqui se obtiene los parametros
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
// Aqui ya podriamos mostrar los parametros que obtuvimos
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_primer, container, false);
}
}
Bajo este método nosotros podríamos recibir parámetros desde el activity y mostrarlos en el fragment. Después de todo los fragments están dentro de algún activity. Entonces de ahora en adelante cuando llamemos al fragment usaremos ExampleFragment.newInstance(argumentos)
para abrir el fragment y pasarle argumentos para que este los pueda mostrar o hacer alguna lógica con ellos.
No es difícil de entender y de hecho si no enviaremos ningún dato del activity al fragment podemos crear una clase sin el Factory, como en el siguiente ejemplo.
public class PrimeroFragment extends Fragment {
public PrimeroFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_day_mode, container, false);
}
}
2. Etiqueta fragment
En un tutorial anterior vimos que para colocar un fragment dentro de un activity usamos el widget FrameLayout. Sin embargo, existe una etiqueta XML que también podemos utilizar para tal fin. Esta es la etiqueta fragment
.
<fragment
android:id="@+id/frag1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:name="com.andygeek.comunicationfragmentsjava.EviaFragment"/>
A diferencia del FrameLayout usando fragment
podemos definir desde el XML que Fragment queremos que lo llene. Para hacer esto usamos el atributo llamado android:name
en el cual podremos colocar la dirección de nuestro fragment.
3. La comunicación
Primero crearemos una interface llamada Comunicador
que implemente un método enviar que funcionará como un contenedor para el dato que deseamos enviar.
public interface Comunicador{
public void enviar(String mensaje);
}
Ahora vamos a implementar esta interface dentro del activity que contiene los dos fragments. Esto nos obligará a sobrescribir el método enviar donde usaremos su parámetro para obtener el mensaje.
public class MainActivity extends AppCompatActivity implements MiFragment.Comunicador {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// El IDE nos pedirá sobreescribir el método enviar de la interface
@Override
public void enviar(String mensaje) {
}
}
Para lo siguiente debemos tener en cuanta que los fragments no tienen contexto, obtienen su contexto del activity que lo contiene. También debemos tener en cuenta que el activity al implementar el Comunicador
por polimorfismo ya puede ser casteado con un objeto Comunicador
. Así que vamos a utilizar estos conceptos en el método onAttach()
del fragment, que es el primer método del ciclo de vida y donde el fragment obtiene el contexto del activity.
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
comunicador = (Comunicador) context;
}
Entonces ahora nuestro comunicador
es una representación del contexto del activity. Así que lo podemos utilizar para ejecutar algún método que está definido en el activity por ejemplo el enviar
. Así estamos ejecutando código del activity en el fragment. Sorprendente verdad!!
Entonces ahora definimos bien lo que queremos ejecutar con el método enviar()
del activity.
@Override
public void enviar(String mensaje) {
// Creamos una referencia del segundo Fragment en nuestro activity
RecibeFragment recibeFragment = (RecibeFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_recibe);
// Utilizamos la referencia creada para ejecutar el método recibir del segundo Fragment,
// pero antes debemos implementar el método recibir en el fragment
recibeFragment.recibir(mensaje);
// Para evitarnos errores podemos verificar si el segundo Fragment está instanciado o no
/*
if(recibe != null){
recibeFragment.recibirTexto(envia);
}
*/
}
El método recibir()
es bastante simple. Solo tiene que ser publico e implementar lo que hará con el mensaje recibido.
public void recibir(String mensaje){
// Cambiamos el texto de un TextView con el mensaje que recibiremos.
txt_recibe.setText(mensaje);
}
4. Tu turno
Usando estos conceptos que acabamos de aprender te animo a realizar el siguiente proyecto. Una aplicación de un solo activity pero con dos fragments en su interior donde el primer fragment enviará información al segundo fragment.
Cuando quieras puedes ver el código del proyecto terminado. Pero ándale inténtalo tu mismo!!
5. El código
El código de este proyecto está en el siguiente repositorio de GitHub: github.com/andygeek/ComunicacionFragmentsJava