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
  2. Etiqueta fragment
  3. La comunicación
  4. Tu turno
  5. El código

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.

Si queremos usar las sugerencias en el editor XML de Android Studio podemos usar Control + Espacio.

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!!

En suma, el comunicador es un objeto activity que puede ejecutar el método enviar que esta definido en el activity. Y como tenemos un parametro en el método enviar podemos usar ese parametro para enviar datos del fragment al activity.

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