11

Tengo una actividad que carga una lista de datos desde el servidor utilizando devoluciones de llamadas del cargador. Tengo hacer una lista de los datos en un fragmento que se extiendecometer fragmento de onLoadFinished dentro de la actividad

SherlockListFragment 

he intentado cometer el fragmento usando

Fragment newFragment = CategoryFragment.newInstance(mStackLevel,categoryList); 
FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 
ft.add(R.id.simple_fragment, newFragment).commit(); 

en onLoadFinished y se da una IllegalStateException diciendo

java.lang.IllegalStateException: Can not perform this action inside of onLoadFinished 

que tienen se refirió al ejemplo en sherlock de barra de acción, pero esos ejemplos tienen cargadores dentro de los fragmentos y no la actividad.

¿Alguien me puede ayudar con esto o que puedo solucionarlo sin tener que llamar al cargador desde el fragmento?

+0

posible duplicado de [Android - problemas usando FragmentActivity + cargador para actualizar FragmentStatePagerAdapter] (http://stackoverflow.com/questions/7746140/android-problems-using-fragmentactivity-loader- to-update-fragmentstatepagera) – rds

Respuesta

14

Atlast, he encontrado una solución a este problema. Cree un manipulador configurando un mensaje vacío y llame a ese manejador onLoadFinished(). El código es similar a esto.

@Override 
public void onLoadFinished(Loader<List<Station>> arg0, List<Station> arg1) { 
    // do other actions 
    handler.sendEmptyMessage(2); 
} 

En el controlador,

private Handler handler = new Handler() { // handler for commiting fragment after data is loaded 
    @Override 
    public void handleMessage(Message msg) { 
     if(msg.what == 2) { 
      Log.d(TAG, "onload finished : handler called. setting the fragment."); 
      // commit the fragment 
     } 
    } 
}; 

El número de fragmentos dependen del requisito.

This method can be mainly used in case of stackFragments, where all fragments have different related functions. 
+1

Hmm Yo desaconsejaría esto. Si realmente necesita apilar fragmentos como dice, entonces simplemente puede llamar a commitAllowingStateLoss(). Esto evitará el controlador y la IllegalArgumentException como le estarías diciendo a la plataforma ... "está bien, soy consciente de los riesgos ... hazlo de todos modos". Ver [enlace] (https://developer.android.com/reference/android/support/v4/app/FragmentTransaction.html#commitAllowingStateLoss()) – kwazi

+0

Gracias kwazi, había probado ese método. Gracias por tu ayuda. Ese fue un buen consejo. Cheers :) – DroidBee

+4

Solo una nota: llamar a commitAllowStateLoss no es una opción cuando se llama a DialogFragment.show(). Tuve que usar un controlador para ese tipo particular de transacción de fragmentos. – javahead76

8

De acuerdo con la documentación de Android en el método onLoadFinished():

Tenga en cuenta que normalmente no se permite una aplicación para cometer transacciones fragmento mientras que en esta llamada, ya que puede suceder después del estado de una actividad se guarda. Ver FragmentManager.openTransaction() para mayor discusión sobre esto.

https://developer.android.com/reference/android/app/LoaderManager.LoaderCallbacks.html#onLoadFinished(android.content.Loader, D)

(Nota: copiar/pegar que enlace en su navegador ... stackoverflow no está manejando bien ..)

Así que simplemente nunca se debe cargar un fragmento en el que se estado. Si realmente no desea colocar el Loader en el Fragment, entonces necesita inicializar el fragmento en su método onCreate() de la Actividad, y luego cuando ocurre el OnLoadFinished, simplemente llame a un método en su fragmento.

Algunos código de seudo áspera sigue:

public class DummyFragment { 

    public void setData(Object someObject) { 
      //do stuff 
    } 

public class DummyActivity extends LoaderCallbacks<Object> { 

    public void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 

      Fragment newFragment = DummyFragment.newInstance(); 
      FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); 
      ft.add(R.id.simple_fragment, newFragment).commit(); 

      getSupportLoaderManager.initLoader(0, null, this) 
    } 

    // put your other LoaderCallbacks here... onCreateLoader() and onLoaderReset() 

    public void onLoadFinished(Loader<Object> loader, Object result) { 
      Fragment f = getSupportLoaderManager.findFragmentById(R.id.simple_fragment); 
      f.setData(result); 
    } 

Obviamente, usted desea utilizar el objeto correcto .. y el cargador de la derecha, y, probablemente, se define un método útil setData() para actualizar su fragmento . Pero, con suerte, esto lo orientará en la dirección correcta.

+0

Gracias por su respuesta! :) Quizás no estaba claro sobre mi pregunta. Ya tengo mi fragmento de inicio enfocado, solo quería implementar el apilamiento del siguiente fragmento, al cargar algunos datos. Encontré un método para mejorar eso. Lo publicaré como una respuesta. +1 por su apoyo y respuesta. Realmente no pensé en usar f.setData (resultado) que podría haber usado en la misma actividad dentro de otros fragmentos. :) – DroidBee

+0

Ah, no era consciente. De todos modos, vea mi comentario sobre su respuesta con respecto a una mejor solución. commitAllowingStateLoss() sería el camino a seguir ... – kwazi

0

Como @kwazi respondió esta es una mala experiencia de usuario para llamar FragmentTransition.commit() de onLoadFinished(). He encontrado una solución para este evento usando ProgressDialog.

Primera creado ProgressDialog.setOnDismissListener(new listener) para ver el onLoadFinished(). Además hago progressDialog.show() antes getLoaderManager().restartLoader(). Y finalmente coloque progressDialog.dismiss() en onLoadFinished(). Dicho enfoque permite no unir la rosca de la IU principal y la rosca del cargador.

public class FrPersonsListAnswer extends Fragment 
 
\t \t \t \t \t \t implements 
 
\t \t \t \t \t \t LoaderCallbacks<Cursor>{ 
 
private ProgressDialog progressDialog; 
 
           \t @Override 
 
\t public View onCreateView(LayoutInflater inflater, 
 
\t \t \t ViewGroup container, Bundle savedInstanceState) { 
 
\t \t View view = inflater.inflate(R.layout.fragment_persons_list, container, false); 
 
\t \t 
 
\t \t //prepare progress Dialog 
 
\t \t progressDialog = new ProgressDialog(curActivity); 
 
\t \t progressDialog.setMessage("Wait..."); 
 
\t \t progressDialog.setIndeterminate(true); 
 
\t \t progressDialog.setOnDismissListener(new OnDismissListener() { 
 
\t \t \t 
 
\t \t \t @Override 
 
\t \t \t public void onDismiss(DialogInterface dialog) { 
 
\t \t \t \t //make FragmentTransaction.commit() here; 
 
\t \t \t \t 
 
\t \t \t \t //but it's recommended to pass control to your Activity 
 
\t \t \t \t //via an Interface and manage fragments there. 
 
\t \t \t } 
 
\t \t }); 
 
\t \t 
 
\t \t lv = (ListView) view.findViewById(R.id.lv_out1); 
 
\t \t lv.setOnItemClickListener(new OnItemClickListener() { 
 

 
\t \t \t @Override 
 
\t \t \t public void onItemClick(AdapterView<?> parent, final View view, 
 
\t \t \t \t \t final int position, long id) { 
 
\t \t \t \t 
 
\t \t \t \t //START PROGRESS DIALOG HERE 
 
\t \t \t \t progressDialog.show(); 
 
\t \t \t \t 
 
\t \t \t \t Cursor c = (Cursor) parent.getAdapter().getItem(position); 
 

 
\t \t \t \t // create Loader 
 
\t \t \t \t getLoaderManager().restartLoader(1, \t null, curFragment); 
 
\t \t \t } 
 
\t \t }); 
 

 
\t \t return view; 
 
\t } 
 
    
 
\t @Override 
 
\t public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 
 
\t \t switch (loader.getId()) { 
 
\t \t case 1: 
 
\t \t \t //dismiss dialog and call progressDialog.onDismiss() listener 
 
\t \t \t progressDialog.dismiss(); 
 
\t \t \t break; 
 

 
\t \t default: 
 
\t \t \t break; 
 
\t \t } 
 
\t }

Cuestiones relacionadas