Si declaro un fragmento en un diseño XML, ¿cómo le paso un paquete?

7 minutos de lectura

Tengo una actividad que he reemplazado con un fragmento. La actividad tomó una intención que tenía información adicional sobre qué datos se suponía que mostraría la actividad.

Ahora que mi Actividad es solo un envoltorio alrededor de un Fragmento que hace el mismo trabajo, ¿cómo llevo ese paquete al Fragmento si declaro el fragmento en XML con la etiqueta?

Si tuviera que usar una FragmentTransaction para colocar el Fragmento en un ViewGroup, tendría la oportunidad de pasar esta información al constructor Fragment, pero me pregunto sobre la situación en la que el fragmento se define en XML.

  • Prueba esto, stackoverflow.com/questions/8641575/…

    –Ashish Dwivedi

    2 de noviembre de 2017 a las 9:06

  • es muy fácil, mira la excelente respuesta de @DanieleSegato

    – Gordito

    12 abr 2021 a las 18:54

avatar de usuario
CommonsWare

Ahora que mi Actividad es solo un envoltorio alrededor de un Fragmento que hace el mismo trabajo, ¿cómo llevo ese paquete al Fragmento si declaro el fragmento en XML con la etiqueta?

no puedes

Sin embargo, le invitamos a llamar findFragmentById() en tu FragmentManager para recuperar el fragmento después de la inflación, luego llame a algún método en el fragmento para asociar datos con él. Si bien aparentemente eso no puede ser setArguments()su fragmento podría organizarse para retener los datos en sí más allá de un cambio de configuración por algún otro medio (onSaveInstanceState(), setRetainInstance(true)etc.).

  • Cuando hice esta pregunta, decidí ir por un camino diferente. Pero justo hoy, tuve una situación similar y volví a esta publicación. Pensé en darle una oportunidad. La solución setArguments no parece funcionar: 10-24 12:48:33.276: E/AndroidRuntime(21417): Provocado por: java.lang.IllegalStateException: Fragmento ya activo Voy a intentar simplemente llamar a un método en el Fragmento.

    – Plantaje

    24/10/2013 a las 17:50


  • Me encontré con la misma IllegalStateException el otro día. El problema parece ser que necesitas llamar setContentView() para que los Fragmentos se inflen. Pero setContentView() también los adjunta a la actividad, lo que hace que sea demasiado tarde para llamar setArguments().

    – Miguel

    24 de enero de 2014 a las 18:44

  • Esto no debe marcarse como correcto. es incorrecto Según la documentación del fragmento (desarrollador.android.com/reference/android/app/…, se debe llamar a setArguments() antes de que el fragmento se adjunte a la actividad. Si puede encontrar el fragmento a través de findFragmentById(), entonces el fragmento ya se adjuntó. Consulte stackoverflow.com/questions/21403040/… para conocer la solución correcta.

    – Neil Sainsbury

    18 de marzo de 2014 a las 0:13


  • @Neil: Puedo entender la fuente de tu confusión. He hecho una pequeña edición para aclarar el momento de la setArguments() llamar.

    – CommonsWare

    18 de marzo de 2014 a las 0:51

  • Consulte stackoverflow.com/questions/18124150/… para obtener opciones sobre cómo pasar datos a un Fragmento definido por XML.

    – La cosa

    12/08/2014 a las 23:37

No es una forma encapsulada, pero terminé “sacando” el paquete de la actividad principal:

Bundle bundle = getActivity().getIntent().getExtras();

avatar de usuario
daniele segato

No puede pasar un paquete (a menos que infle su fragmento mediante programación en lugar de hacerlo a través de XML), pero PUEDE pasar parámetros (o más bien atributos) a través de XML a un fragmento.

El proceso es similar a cómo se definen Ver atributos personalizados. Excepto que AndroidStudio (actualmente) no lo ayuda en el proceso.

supongamos que este es su fragmento usando argumentos (usaré kotlin pero también funciona totalmente en Java):

class MyFragment: Fragment() {

    // your fragment parameter, a string
    private var screenName: String? = null

    override fun onAttach(context: Context?) {
        super.onAttach(context)
        if (screenName == null) {
            screenName = arguments?.getString("screen_name")
        }
    }
}

Y quieres hacer algo como esto:

<fragment
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/myFragment"
    android:name="com.example.MyFragment"
    app:screen_name="@string/screen_a"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

Nota la app:screen_name="@string/screen_a"

para que funcione simplemente agregue esto en un archivo de valores (fragment_attrs.xml o elige el nombre que quieras):

<!-- define your attribute name and type -->
<attr name="screen_name" format="string|reference"/>

<!-- define a bunch of constants you wanna use -->
<string name="screen_a" translatable="false">ScreenA</string>
<string name="screen_b" translatable="false">ScreeenB</string>

<!-- now define which arguments your fragment is gonna have (can be more then one) -->
<!-- the convention is "FragmentClassName_MembersInjector" -->
<declare-styleable name="MyFragment_MembersInjector">
    <attr name="screen_name"/>
</declare-styleable>

Casi listo, solo necesita leerlo en su fragmento, así que agregue el método:

override fun onInflate(context: Context?, attrs: AttributeSet?, savedInstanceState: Bundle?) {
    super.onInflate(context, attrs, savedInstanceState)
    if (context != null && attrs != null && screenName == null) {
        val ta = context.obtainStyledAttributes(attrs, R.styleable.MyFragment_MembersInjector)
        if (ta.hasValue(R.styleable.MyFragment_MembersInjector_screen_name)) {
            screenName = ta.getString(R.styleable.MyFragment_MembersInjector_screen_name)
        }
        ta.recycle()
    }
}

et voilá, tus atributos XML en tu fragmento 🙂

Limitaciones:

  • Android Studio (a partir de ahora) no autocompleta dichos argumentos en el diseño XML
  • no puedes pasar Parcelable pero solo lo que se puede definir como Atributos de Android

  • Esto es lo que necesitaba. Muchas gracias.

    – bikram

    25 de julio de 2019 a las 6:35

  • Salvador, justo lo que estaba buscando.

    –Yuvraj Pandey

    13 oct 2019 a las 8:32

avatar de usuario
Zapnologica

Otra opción es no declarar el fragmento en el XML. Sé que no es exactamente lo que quieres hacer. Sin embargo, podría declarar un diseño simple en su vista como este:

    <LinearLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" />

Y luego en tu Activity class, infla programáticamente el diseño con el fragmento. De esta manera, puede pasar a través de parámetros usando argumentos.

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MyFragment fragment = MyFragment.newInstance();
Bundle args = new Bundle();
args.putInt(Global.INTENT_INT_ROLE, 1);
fragment.setArguments(args);
fragmentTransaction.add(R.id.fragment_container, fragment, "MyActivity");
fragmentTransaction.commit();

En el fragmento,

if (getArguments() != null) {
   int role = getArguments().getInt(Global.INTENT_INT_ROLE); }

Este enfoque no es tan limpio y simple como declararlo en el xml; sin embargo, me he mudado a él porque te da mucho más control sobre el fragmento.

avatar de usuario
ASADI

Sé que es una respuesta demasiado tarde, pero creo que alguien necesita eso 🙂

Solo en anulación de actividad onAttachFragment()

@Override
public void onAttachFragment(Fragment fragment)
{
    super.onAttachFragment(fragment);

    if (fragment.getId() == R.id.frgBlank)
    {
        Bundle b = new Bundle();
        b.putString("msg", "Message");

        fragment.setArguments(b);
    }
}

y en el fragmento del método onCreateView

Bundle b = getArguments();
if (b != null)
{
    Toast.makeText(getBaseContext(), b.getString("msg"), Toast.LENGTH_SHORT).show();
}

La única solución que veo es no usar los argumentos como canal de intercambio de datos. En su lugar, haga su fragmento para obtener la información necesaria de otro lugar. Vuelva a llamar para obtener la actividad adecuada, consulte una memoria de almacenamiento temporal, un objeto Singleton, etc.

Otra solución que puede ser útil es emplear marcos que permitan que objetos no relacionados intercambien mensajes a través del patrón de diseño Mediator, como Otón.

avatar de usuario
Roop Kishore

este enfoque funcionó para mí.

No pasará el paquete desde cualquier lugar, sino que puede establecer los argumentos en el método onAttach en el propio fragmento.

y más adelante en los métodos de ciclo de vida de los fragmentos, puede usar esos argumentos de paquete.

override fun onAttach(context: Context) {
        super.onAttach(context)
        if(arguments == null){
            val bundle = Bundle()
            bundle.putString("mykey", "myvalue")
            arguments = bundle
        }
    }

Cualquiera podría hacer una pregunta, por qué establecer los argumentos en el fragmento mientras podemos usar directamente los valores en los lugares utilizables. Es correcto, pero este enfoque también puede funcionar cuando pasará estos argumentos a otras clases, digamos cualquier modelo de vista.

por ejemplo

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        /*
         Here I am passing these arguments to a viewmodel 
        */
        viewModel.prepareData(arguments) 
        
        --------
        --------
        --------

    }

Gracias.

¿Ha sido útil esta solución?