tutorial studio navegar fragments example entre ejemplo activity android android-fragments

studio - java android fragment



¿Realmente los fragmentos necesitan un constructor vacío? (4)

Aquí está mi solución simple:

1 - Define tu fragmento

public class MyFragment extends Fragment { private String parameter; public MyFragment() { } public void setParameter(String parameter) { this.parameter = parameter; } }

2 - Crea tu nuevo fragmento y llena el parámetro

myfragment = new MyFragment(); myfragment.setParameter("here the value of my parameter");

3 - ¡Disfrútalo!

Obviamente puedes cambiar el tipo y la cantidad de parámetros. Rapido y Facil.

Tengo un Fragment con un constructor que toma múltiples argumentos. Mi aplicación funcionó bien durante el desarrollo, pero en producción mis usuarios a veces ven este bloqueo:

android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment make sure class name exists, is public, and has an empty constructor that is public

Podría hacer un constructor vacío como sugiere este mensaje de error, pero eso no tiene sentido para mí desde entonces, tendría que llamar a un método separado para terminar de configurar el Fragment .

Tengo curiosidad por saber por qué este accidente sólo ocurre de vez en cuando. Tal vez estoy usando el ViewPager incorrectamente? Yo mismo hago una instancia de todos los Fragment y los guardo en una lista dentro de la Activity . No uso las transacciones de FragmentManager , ya que los ejemplos de ViewPager que he visto no lo requerían y todo parecía funcionar durante el desarrollo.


Como lo señaló CommonsWare en esta pregunta https://.com/a/16064418/1319061 , este error también puede ocurrir si está creando una subclase anónima de un Fragmento, ya que las clases anónimas no pueden tener constructores.

No hagas subclases anónimas de Fragmento :-)


Ellos si.

De todos modos, no deberías estar anulando al constructor. Debe tener un método estático newInstance() definido y pasar cualquier parámetro mediante argumentos (paquete)

Por ejemplo:

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

Y por supuesto agarrando los argumentos de esta manera:

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

Entonces usted podría crear una instancia de su administrador de fragmentos de esta manera:

@Override public void onCreate(Bundle savedInstanceState) { if (savedInstanceState == null){ getSupportFragmentManager() .beginTransaction() .replace(R.id.content, MyFragment.newInstance( R.string.alert_title, "Oh no, an error occurred!") ) .commit(); } }

De esta manera, si se desconecta y se vuelve a adjuntar, el estado del objeto se puede almacenar a través de los argumentos. Al igual que los paquetes adjuntos a los intentos.

Razón - Lectura extra

Pensé que explicaría por qué para la gente que se pregunta por qué.

Si marca: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/Fragment.java

Verá que el método de instantiate(..) en la clase Fragment llama al método newInstance :

public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) { try { Class<?> clazz = sClassMap.get(fname); if (clazz == null) { // Class not found in the cache, see if it''s real, and try to add it clazz = context.getClassLoader().loadClass(fname); if (!Fragment.class.isAssignableFrom(clazz)) { throw new InstantiationException("Trying to instantiate a class " + fname + " that is not a Fragment", new ClassCastException()); } sClassMap.put(fname, clazz); } Fragment f = (Fragment) clazz.getConstructor().newInstance(); if (args != null) { args.setClassLoader(f.getClass().getClassLoader()); f.setArguments(args); } return f; } catch (ClassNotFoundException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", e); } catch (java.lang.InstantiationException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", e); } catch (IllegalAccessException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an" + " empty constructor that is public", e); } catch (NoSuchMethodException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": could not find Fragment constructor", e); } catch (InvocationTargetException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": calling Fragment constructor caused an exception", e); } }

http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#newInstance() Explica por qué, al instanciarse, comprueba que el accesor es public y que ese cargador de clases le permite acceder .

Es un método bastante desagradable en general, pero permite que FragmentManger mate y Fragments crear Fragments con estados. (El subsistema Android hace cosas similares con Activities ).

Clase de ejemplo

Me preguntan mucho sobre cómo llamar a newInstance , (no confunda esto con el método de clase. Este ejemplo de toda la clase debería mostrar el uso.

/** * Created by chris on 21/11/2013 */ public class StationInfoAccessibilityFragment extends BaseFragment implements JourneyProviderListener { public static final StationInfoAccessibilityFragment newInstance(String crsCode) { StationInfoAccessibilityFragment fragment = new StationInfoAccessibilityFragment(); final Bundle args = new Bundle(1); args.putString(EXTRA_CRS_CODE, crsCode); fragment.setArguments(args); return fragment; } // Views LinearLayout mLinearLayout; /** * Layout Inflater */ private LayoutInflater mInflater; /** * Station Crs Code */ private String mCrsCode; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mCrsCode = getArguments().getString(EXTRA_CRS_CODE); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mInflater = inflater; return inflater.inflate(R.layout.fragment_station_accessibility, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mLinearLayout = (LinearLayout)view.findViewBy(R.id.station_info_accessibility_linear); //Do stuff } @Override public void onResume() { super.onResume(); getActivity().getSupportActionBar().setTitle(R.string.station_info_access_mobility_title); } // Other methods etc... }


Sí, como puede ver, el paquete de soporte también crea una instancia de los fragmentos (cuando se destruyen y se vuelven a abrir). Las subclases de Fragemnt necesitan un constructor vacío público ya que esto es lo que llama el marco.