Práctica recomendada para instanciar un nuevo fragmento de Android

He visto dos prácticas generales para instanciar un nuevo Fragmento en una aplicación:

Fragment newFragment = new MyFragment(); 

y

 Fragment newFragment = MyFragment.newInstance(); 

La segunda opción hace uso de un método estático newInstance() y generalmente contiene el siguiente método.

 public static Fragment newInstance() { MyFragment myFragment = new MyFragment(); return myFragment; } 

Al principio, pensé que el principal beneficio era el hecho de que podría sobrecargar el método newInstance () para dar flexibilidad al crear nuevas instancias de un Fragmento – pero también podría hacer esto mediante la creación de un constructor sobrecargado para el Fragmento.

¿Me he perdido algo?

¿Cuáles son los beneficios de un enfoque sobre el otro? ¿O es sólo una buena práctica?

Si Android decide volver a crear tu Fragmento más tarde, llamará al constructor sin argumentos de tu fragmento. Por lo tanto, la sobrecarga del constructor no es una solución.

Con eso dicho, la manera de pasar la materia a su fragmento de modo que estén disponibles después de que un fragmento sea recreado por Androide es pasar un paquete al método de setArguments .

Así, por ejemplo, si queríamos pasar un número entero al fragmento, usaríamos algo como:

 public static MyFragment newInstance(int someInt) { MyFragment myFragment = new MyFragment(); Bundle args = new Bundle(); args.putInt("someInt", someInt); myFragment.setArguments(args); return myFragment; } 

Y más adelante en el fragmento onCreate() puedes acceder a ese entero usando:

 getArguments().getInt("someInt", 0); 

Este Bundle estará disponible incluso si el Fragmento es de alguna manera recreado por Android.

También tenga en cuenta: setArguments sólo se puede llamar antes de que el Fragmento se adjunte a la Actividad.

Este enfoque también se documenta en la referencia del desarrollador android: https://developer.android.com/reference/android/app/Fragment.html

El único beneficio en el uso de la newInstance() que veo son los siguientes:

  1. Tendrás un solo lugar donde todos los argumentos usados ​​por el fragmento podrían ser agrupados y no tienes que escribir el código debajo de cada instancia de un fragmento.

     Bundle args = new Bundle(); args.putInt("someInt", someInt); args.putString("someString", someString); // Put any other arguments myFragment.setArguments(args); 
  2. Es una buena manera de decir a otras clases qué argumentos espera que funcione fielmente (aunque debería ser capaz de manejar casos si no hay argumentos incluidos en la instancia de fragmentos).

Por lo tanto, mi opinión es que el uso de una newInstance() estática newInstance() para instanciar un fragmento es una buena práctica.

Hay también otra manera:

 Fragment.instantiate(context, MyFragment.class.getName(), myBundle) 

Mientras @yydl da una razón convincente sobre por qué el método newInstance es mejor:

Si Android decide volver a crear tu Fragmento más tarde, llamará al constructor sin argumentos de tu fragmento. Por lo tanto, la sobrecarga del constructor no es una solución.

Todavía es posible utilizar un constructor . Para ver por qué esto es, primero debemos ver por qué la solución anterior es utilizada por Android.

Antes de poder utilizar un fragmento, se necesita una instancia. Android llama a YourFragment() (el constructor sin argumentos ) para construir una instancia del fragmento. Aquí cualquier constructor sobrecargado que escriba será ignorado, ya que Android no puede saber cuál usar.

En la vida de una actividad el fragmento se crea como se mencionó anteriormente y se destruye varias veces por Android. Esto significa que si coloca los datos en el objeto fragmento en sí, se perderá una vez que el fragmento se destruye.

Para solucionarlo, android le pide que almacene datos usando un Bundle (llamando setArguments() ), que luego se puede acceder desde YourFragment . Los bundle argumentos están protegidos por Android, por lo que se garantiza su persistencia .

Una forma de establecer este paquete es mediante un método newInstance estático:

 public static YourFragment newInstance (int data) { YourFragment yf = new YourFragment() /* See this code gets executed immediately on your object construction */ Bundle args = new Bundle(); args.putInt("data", data); yf.setArguments(args); return yf; } 

Sin embargo, un constructor:

 public YourFragment(int data) { Bundle args = new Bundle(); args.putInt("data", data); setArguments(args); } 

Puede hacer exactamente lo mismo que el método newInstance .

Naturalmente, esto fallaría, y es una de las razones por las que Android quiere que utilice el método newInstance :

 public YourFragment(int data) { this.data = data; // Don't do this } 

Como explicación adicional, aquí está Android Fragment Class:

 /** * Supply the construction arguments for this fragment. This can only * be called before the fragment has been attached to its activity; that * is, you should call it immediately after constructing the fragment. The * arguments supplied here will be retained across fragment destroy and * creation. */ public void setArguments(Bundle args) { if (mIndex >= 0) { throw new IllegalStateException("Fragment already active"); } mArguments = args; } 

Tenga en cuenta que Android pide que los argumentos se establezcan sólo en la construcción, y garantiza que estos se mantendrán.

EDIT : Como se señala en los comentarios de @ JHH, si está proporcionando un constructor personalizado que requiere algunos argumentos, Java no proporcionará su fragmento con un constructor no arg por defecto. Así que esto requeriría que usted definiera un constructor no arg , que es el código que podría evitarse con el método newInstance .

EDIT : Android no permite el uso de un constructor sobrecargado de fragmentos más. Debe utilizar el método newInstance .

No estoy de acuerdo con la respuesta yydi diciendo:

Si Android decide volver a crear tu Fragmento más tarde, llamará al constructor sin argumentos de tu fragmento. Por lo tanto, la sobrecarga del constructor no es una solución.

Pienso que es una solución y una buena, ésta es exactamente la razón por la que fue desarrollada por el lenguaje de la base de Java.

Es cierto que el sistema Android puede destruir y recrear su Fragment . Así que usted puede hacer esto:

 public MyFragment(){ // An empty constructor for Android System to use, otherwise exception may occur. } public MyFragment(int someInt) { Bundle args = new Bundle(); args.putInt("someInt", someInt); setArguments(args); } 

Te permitirá extraer someInt de getArguments() posteriormente, aunque el Fragment haya sido recreado por el sistema. Esta es una solución más elegante que static constructor static .

Para mi opinión constructores static son inútiles y no deben ser utilizados. También te limitarán si en el futuro quisieras extender este Fragment y añadir más funcionalidad al constructor. Con static constructor static no se puede hacer esto.

Actualizar:

Android añadió inspección que marca todos los constructores no predeterminados con un error.
Recomiendo desactivarlo, por las razones mencionadas anteriormente.

Dado que las preguntas sobre las mejores prácticas, añadiría, que a menudo una buena idea para utilizar el enfoque híbrido para la creación de fragmentos cuando se trabaja con algunos servicios web REST

No podemos pasar objetos complejos, por ejemplo algún modelo de usuario, para el caso de mostrar el fragmento de usuario

Pero lo que podemos hacer, es comprobar en onCreate que el usuario! = Nulo y si no – entonces lo traen de la capa de datos, de lo contrario – utilizar existentes.

De esta manera ganamos tanto la capacidad de recrear por userId en caso de fragmentación de la recreación por Android y snappiness para las acciones del usuario, así como la capacidad de crear fragmentos mediante la celebración de objeto en sí o sólo es id

Algo le gusta:

 public class UserFragment extends Fragment { public final static String USER_ID="user_id"; private User user; private long userId; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); userId = getArguments().getLong(USER_ID); if(user==null){ // // Recreating here user from user id(ie requesting from your data model, // which could be services, direct request to rest, or data layer sitting // on application model // user = bringUser(); } } public static UserFragment newInstance(User user, long user_id){ UserFragment userFragment = new UserFragment(); Bundle args = new Bundle(); args.putLong(USER_ID,user_id); if(user!=null){ userFragment.user=user; } userFragment.setArguments(args); return userFragment; } public static UserFragment newInstance(long user_id){ return newInstance(null,user_id); } public static UserFragment newInstance(User user){ return newInstance(user,user.id); } } 

setArguments() es inútil. Sólo trae un lío.

 public class MyFragment extends Fragment { public String mTitle; public String mInitialTitle; public static MyFragment newInstance(String param1) { MyFragment f = new MyFragment(); f.mInitialTitle = param1; f.mTitle = param1; return f; } @Override public void onSaveInstanceState(Bundle state) { state.putString("mInitialTitle", mInitialTitle); state.putString("mTitle", mTitle); super.onSaveInstanceState(state); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) { if (state != null) { mInitialTitle = state.getString("mInitialTitle"); mTitle = state.getString("mTitle"); } ... } } 

La mejor práctica para fragmentar instancias con argumentos en android es tener un método estático de fábrica en tu fragmento.

 public static MyFragment newInstance(String name, int age) { Bundle bundle = new Bundle(); bundle.putString("name", name); bundle.putInt("age", age); MyFragment fragment = new MyFragment(); fragment.setArguments(bundle); return fragment; } 

Debe evitar configurar sus campos con la instancia de un fragmento. Porque cada vez que el sistema android recrea su fragmento, si siente que el sistema necesita más memoria, que recreará su fragmento utilizando constructor sin argumentos.

Puede encontrar más información sobre las mejores prácticas para instanciar fragmentos con argumentos aquí.

La mejor manera de instanciar el fragmento es usar el método por defecto Fragment.instantiate o crear un método factory para instanciar el fragmento
Precaución: crear siempre un constructor vacío en el fragmento otro mientras que la restauración de la memoria del fragmento lanzará la excepción run-time.

Creo que tengo una solución mucho más simpeler para esto.

 public class MyFragment extends Fragment{ private String mTitle; private List<MyObject> mObjects; public static MyFragment newInstance(String title, List<MyObject> objects) MyFragment myFrag = new MyFragment(); myFrag.mTitle = title; myFrag.mObjects = objects; return myFrag; } 
  • Ocultar el indicador "Cargando ..." al implementar un ListFragment
  • La recreación de fragmentos de ViewPager se reanuda pero no se ve
  • ¿Por qué onResume método de un fragmento nunca se disparó después de despedir un DialogFragment que se inició desde el fragmento?
  • Cómo mostrar / ocultar fragmento con el dedo hacia arriba / hacia abajo como la aplicación androide de soundcloud
  • ¿Cómo agrego un Fragmento de Android a mi FragmentActivity?
  • Android: restaurar fragmentos después de cambiar la orientación de la pantalla
  • Fragmento de Android La transacción con animación provoca que el flash blanco
  • Coordinador
  • ¿Se llamará onSaveInstanceState a fragmentos en la pila trasera?
  • Qué opciones existen para mantener la compatibilidad con Android 1.5 después de la implementación de fragmentos
  • Cómo cambiar los fragmentos con el cajón de navegación de Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.