¿Por qué quiero evitar constructores no predeterminados en fragmentos?

173

Estoy creando una aplicación con Fragmentsy en uno de ellos, creé un constructor no predeterminado y recibí esta advertencia:

Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(Bundle) instead

¿Alguien puede decirme por qué no es una buena idea?

¿Me puede sugerir también cómo podría lograr esto?

public static class MenuFragment extends ListFragment {
    public ListView listView1;
    Categories category;

    //this is my "non-default" constructor
    public MenuFragment(Categories category){
        this.category = category;
    }....

¿Sin usar el constructor no predeterminado?

BlackHatSamurai
fuente
3
No, esos no ayudan. No respondieron mi pregunta. Pero gracias de todos
modos
31
@BlaineOmega En realidad este en particular: stackoverflow.com/a/11602478/321697 definitivamente responde a su pregunta. En un cambio de orientación u otro evento que hace que se vuelva a crear el Fragmento, Android usa el constructor predeterminado, así como el Paquete pasado como argumento. Si está utilizando un constructor personalizado, tan pronto como se vuelva a crear el fragmento debido a uno de estos eventos, se pierde todo lo que hizo en el constructor personalizado.
Kevin Coppock
1
Gracias, pero eso responde el por qué, pero no el cómo.
BlackHatSamurai
Eso está cubierto por el primer y segundo enlace en mi comentario original.
CommonsWare

Respuestas:

110

Cree un objeto de paquete e inserte sus datos (en este ejemplo, su Categoryobjeto). Tenga cuidado, no puede pasar este objeto directamente al paquete, a menos que sea serializable. Creo que es mejor construir su objeto en el fragmento y poner solo una identificación u otra cosa en el paquete. Este es el código para crear y adjuntar un paquete:

Bundle args = new Bundle();
args.putLong("key", value);
yourFragment.setArguments(args);

Después de eso, en su fragmento de datos de acceso:

Type value = getArguments().getType("key");

Eso es todo.

nistv4n
fuente
3
¿Cómo pasar un objeto? Quiero pasar un objeto de contexto o cualquier otro objeto.
Adil Malik
12
Los paquetes pueden transportar objetos serializados de Java, así como Parcelableobjetos. Además, no debe pasar un Context, porque se puede acceder a esa información a través del getActivity()método del fragmento .
krakatoa
¿En fragmento dónde hacer esto Type value = getArguments().getType("key");?
Muhammad Babar
44
@ Muhammad Babar: Si yo fuera usted, lo agregaría al newInstance()método. Por ejemplo: public static FragmentName newInstance(your variables){}. Como recomienda la documentación de Android, no cree un constructor con parámetros, porque el predeterminado (sin parámetros) se llamará automáticamente después del reinicio de su fragmento.
nistv4n
@MuhammadBabar onCreateView está bien
chanjianyi
272

Parece que ninguna de las respuestas responde realmente "¿por qué usar paquete para pasar parámetros en lugar de constructores no predeterminados"

La razón por la que debería pasar los parámetros a través del paquete es porque cuando el sistema restaura un fragment(por ejemplo, en el cambio de configuración), restaurará automáticamente su bundle.

Las devoluciones de llamada tienen gusto onCreateo onCreateViewdeberían leer los parámetros del bundle- de esta manera se garantiza que restaurará el estado del fragmentcorrecto al mismo estado con el que fragmentse inicializó (tenga en cuenta que este estado puede ser diferente del onSaveInstanceState bundleque se pasa al onCreate/onCreateView)

La recomendación de usar el newInstance()método estático es solo una recomendación. Puede usar un constructor no predeterminado, pero asegúrese de completar los parámetros de inicialización en el bundleinterior del cuerpo de ese constructor. Y lea esos parámetros en los métodos onCreate()o onCreateView().

numan salati
fuente
2
Bien explicado. Gracias. Si yo fuera el que hiciera la pregunta, te hubiera dado una señal
Karue Benson Karue
55
Ya no puede usar un constructor no predeterminado (por cualquier razón) ... da un error de compilación (solía ser una advertencia).
MPavlak
51

No Fragmentdeberías tener constructores debido a cómo lo FragmentManagerinstancia. Debe tener un newInstance()método estático definido con los parámetros que necesita, luego agruparlos y establecerlos como argumentos del fragmento, a los que luego puede acceder con el Bundleparámetro.

Por ejemplo:

public static MyFragment newInstance(int title, String message) {
    MyFragment fragment = new MyFragment();
    Bundle bundle = new Bundle(2);
    bundle.putInt(EXTRA_TITLE, title);
    bundle.putString(EXTRA_MESSAGE, message);
    fragment.setArguments(bundle);
    return fragment ;
}

Y lea estos argumentos en onCreate:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    title = getArguments().getInt(EXTRA_TITLE);
    message = getArguments().getString(EXTRA_MESSAGE);

    //...
}

De esta manera, si se desconecta y vuelve a adjuntar, el estado del objeto se puede almacenar a través de los argumentos, de forma muy similar a bundlesadjuntar a Intents.

Asaf Pinhassi
fuente
9

Si usa parámetro para alguna clase. prueba esto

SomeClass mSomeInstance;
public static final MyFragment newInstance(SomeClass someInstance){
    MyFragment f = new MyFragment();
    f.mSomeInstance = someInstance;
    return f;
}
김동기
fuente
55
Esto es realmente una mala sugerencia. Una vez que el Fragmento sea recreado por a FragmentManager, perderá mSomeInstance.
Yaroslav Mytkalyk
De acuerdo, SomeClass debe ser parcelable y almacenado en un paquete usando setArguments ()
Jake_
1

Creo que no hay diferencia entre el constructor estático y dos constructores (uno vacío y parametrizado que almacena argumentos en un paquete de argumentos de Fragment), lo más probable es que esta regla general se cree para reducir la probabilidad de olvidar implementar un constructor sin argumentos en Java , que no se genera implícitamente cuando hay sobrecarga presente.

En mis proyectos utilizo Kotlin e implemento fragmentos con un constructor primario sin argumentos y un constructor secundario para argumentos que solo los almacena en un paquete y lo configura como argumentos Fragmento, todo funciona bien.

Pavlus
fuente
0

Si el fragmento usa constructores no predeterminados después de cambiar la configuración, el fragmento perderá todos los datos.

Akop Vardanian
fuente