No se puede realizar esta acción dentro de onLoadFinished

Estoy creando una nueva aplicación de muestra de Android con una actividad y muchos fragmentos.

Al principio estoy empezando el "OverviewFragment" (mi tablero) que debe mostrar algunas informaciones básicas. My OverviewFragment carga las informaciones con un "AccountProvider" (ContentProvider). Si la base de datos está vacía, el OverviewFragment debe reemplazar con mi WelcomeFragment …

Aquí está un código:

public class OverviewFragment extends BaseFragment implements LoaderManager.LoaderCallbacks { private static final int LOADER_ACCOUNTS = 10; private static final int LOADER_TRANSACTIONS = 20; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); getLoaderManager().initLoader(LOADER_ACCOUNTS, null, this); //getLoaderManager().initLoader(LOADER_TRANSACTIONS, null, this); } @Override public Loader onCreateLoader(int id, Bundle args) { Uri uri = null; String[] projection = null; String selection = null; String[] selectionArgs = null; String sortOrder = null; switch (id) { case LOADER_ACCOUNTS: uri = WalletProvider.CONTENT_URI; projection = new String[]{DBHelper.ACC_ID, DBHelper.ACC_TITLE}; sortOrder = DBHelper.ACC_TITLE; break; } CursorLoader cl = new CursorLoader(getActivity(), uri, projection, selection, selectionArgs, sortOrder); return cl; } @Override public void onLoadFinished(Loader loader, Object data) { switch (loader.getId()) { case LOADER_ACCOUNTS: bindAccounts((Cursor) data); break; } } @Override public void onLoaderReset(Loader loader) { } private void bindAccounts(Cursor cursor) { boolean showCreateWallet = true; if (cursor != null && cursor.moveToFirst()) { showCreateWallet = false; } if (showCreateWallet) { listener.changeFragment(new WalletCreateFragment()); } } 

Y aquí mi actividad principal

  @Override public void changeFragment(Fragment fragmentToLoad) { FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.container, fragmentToLoad) .commit(); } 

Ahora … si estoy empezando mi aplicación con una base de datos vacía, obtengo el error que ves en el título ..

Sé que no debería cambiar el fragmento en la función onLoadFinished …. pero ¿dónde puedo hacerlo? :PAG

Lo siento por mi inglés =)

Este es un error de android. Para solucionar esto, utilice un Handler para reemplazar / añadir / llamar a un Fragmento dentro de onLoadFinished como esto:

 final int WHAT = 1; Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { if(msg.what == WHAT) changeFragment(fragmentToLoad); } }; handler.sendEmptyMessage(WHAT); 

Esto no es un error, pero no es un problema simple. onLoadFinished puede ejecutarse en cualquier momento, incluso después de que se haya guardado el estado de una actividad. El cambio resultante del fragmento entonces no será guardado automáticamente por el marco. Tienes que permitirlo explícitamente utilizando commitAllowingStateLoss

En la documentación de onLoadFinished :

Se llama cuando un cargador previamente creado ha terminado su carga. Tenga en cuenta que normalmente no se permite a una aplicación confirmar transacciones de fragmentos mientras está en esta llamada, ya que puede ocurrir después de que se guarde el estado de una actividad. Vea FragmentManager.openTransaction () para más información sobre esto.

Citando Dianne Hackborn del hilo mencionado en el comentario en la otra respuesta :

Basta con entender que si el estado de fragmento de la actividad ya se ha guardado, su código tendrá que actualizarlo correctamente si se reinicia posteriormente desde el estado.

[…]

Es una mala experiencia de usuario mostrar un diálogo (o hacer cualquier otro cambio importante en la interfaz de usuario) como resultado de un cargador. Esto es lo que está haciendo: establecer alguna operación para ejecutar en segundo plano para una cantidad de tiempo en-determinante, que al final puede lanzar algo delante del usuario tirando de ellos fuera de lo que estaban haciendo.

Mi sugerencia es mostrar al usuario cualquier información sobre el resultado del cargador en línea de la misma manera que mostraría los datos de la misma.

Si usted (y sus usuarios) están bien con la experiencia del usuario, puede usar commitAllowingStateLoss para actualizar el fragmento.

Ambas respuestas faltan una buena solución. Es cierto que no es una buena idea hacer algo en el onLoadfinished ya que la actividad o fragmento podría haber sido destruido.

Tampoco es una buena experiencia de usuario actualizar la interfaz de usuario después de que algo en un hilo independiente ha cambiado ya que pueden estar a punto de realizar una acción. Pero eso se puede arreglar con un botón de actualización que luego actualiza lo que el usuario ve.

Sin embargo, hay circunstancias en las que puede requerir actualizar realmente la interfaz de usuario. Por ejemplo, si necesitamos hacer una acción que requiere que el usuario espere después de haber presionado un botón siguiente .

En su ejemplo, usted extiende las Callbacks directamente por el Fragment para que pueda crear un método en su fragmento que le permite ejecutar con seguridad una actualización de la interfaz de usuario de esta manera:

 private void update(Runnable runnable) { View rootView = getView(); if (isAdded() && rootView != null) { rootView.post(runnable); } } 

Esto comprueba si el fragmento está en un estado que puede manejar las actualizaciones de la interfaz de usuario y ejecuta el comando. Se puede utilizar de esta manera:

 update(new Runnable() { @Override public void run() { bindAccounts((Cursor) data); } }) 

Dicho esto, no es una idea muy sabia utilizar su fragmento como las devoluciones de llamada ya que puede LoaderManager su fragmento en LoaderManager que vive en la actividad.

Otra forma segura de manejar esto sería con receptores de radiodifusión (asegúrese de que no estén registrados).

Sin embargo, la opción más segura será utilizar los componentes de arquitectura recientemente anunciados para Android cuando estén listos para la producción:

https://developer.android.com/topic/libraries/architecture/index.html

  • Añadir Fragmento anidado después de que la vista Fragmento de padre ya esté creada
  • Haga clic en ListFragment
  • Memoria retenida por el fragmento
  • Cómo cambiar fragmento de forma programática en FragmentPagerAdapter?
  • Ciclo de vida de Android Fragment sobre cambios de orientación
  • Cómo pasar Bundle de Fragment a Fragment
  • Ejemplo de servicio de primer plano
  • Aplicar tema personalizado a PreferenceFragment
  • Android: Añadir fragmentos con android.R.id.content
  • Pantalla débil e interacción de bloques con hojas de fondo
  • Fragmento superpuesto
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.