16

Al identificar los cargadores en su LoaderManager, usted usa identificadores únicos. Pregunto qué tan únicos deben ser esos identificadores.¿Cuál es el alcance de un LoaderManager?

¿Cada actividad y fragmento tiene su propio LoaderManager? ¿Los fragmentos usan el gestor de carga de la actividad a la que están vinculados? ¿Hay solo un LoaderManager propiedad de la aplicación?

Puntos de bonificación si me puede decir cómo es posible cambiar qué LoaderManager está utilizando. Si quiero que cada fragmento de mi actividad use el mismo LoaderManager (algunos de ellos están extrayendo la misma información y compartir los cargadores sería bueno), ¿es posible?

+3

[** Comprensión del LoaderManager (parte 2) **] (http://www.androiddesignpatterns.com/2012/05/why-you-should-use-loadermanager.html) –

Respuesta

8

Actualmente estoy portando mi aplicación al paquete de compatibilidad de Android (principalmente para CursorLoader y Fragmentos). Actualmente estoy tratando de compartir un CursorLoader entre dos fragmentos para evitar una consulta a mi ContentProvider. ¡Bienvenido a mi mundo! ;)

Un caso de uso simple:.

- DummyActivity extiende FragmentActivity/Log.d (Constants.LOGTAG, "DummyActivity.onCreate" + getSupportLoaderManager() toString());

- DataFragment extends Fragment implementa LoaderManager.LoaderCallbacks/Log.d (Constants.LOGTAG, "DataFragment.onCreate" + getLoaderManager(). ToString());

- ReportFragment extends Fragment implementa LoaderManager.LoaderCallbacks/Log.d (Constants.LOGTAG, "ReportFragment.onCreate" + getLoaderManager(). ToString());

DummyActivity instancia el DataFragment y el último instancia el ReportFragment. La salida de logcat muestra diferentes direcciones para cada LoaderManager. Como primera conclusión, cada Fragmento parece tener un LoaderManager adecuado ...

Voy a continuar y actualizar si puedo responder a su pregunta (nuestra;)). Si ha progresado, comparta su valioso conocimiento.

Actualización:

Mi suposición es que los ID de carga se asocian únicamente con un alcance local de un LoaderManager de un fragmento específico para permitir que varios cargadores locales a asociarse con el fragmento (para que pueda devolver una cargador diferente en onCreateLoader basado en el id int arg y las llamadas initLoader).

Hasta ahora me las arreglé para "reutilizar" un cargador (... o no):

- En primer lugar, me he permitido LoaderManager depuración con getSupportLoaderManager().enableDebugLogging(true); en el método DummyActivity onCreate.

- Luego he llamado a getActivity().getSupportLoaderManager().initLoader(78, null, this); desde los métodos onCreate de DataFragment y ReportFragment.

- DataFragment expone el CursorLoader creado por el método onCreateLoader a través de un setter en un miembro privado de mCursorLoader.

- ReportFragment onCreateLoader devuelve el DataFragment CursorLoader (después de recuperar el Fragment con findFragmentByTag).

La salida logcat filtrada (y ligeramente ofuscado):

 DummyApp D DummyActivity.onCreate 
     DummyApp D DataFragment.newInstance 
     DummyApp D ReportFragment.newInstance 
     DummyApp D DataFragment.onCreate 
LoaderManager V initLoader in LoaderManager{405a19d0 in SpecificAction{4059ee98}}: args=null 
     DummyApp D DataFragment.onCreateLoader 
LoaderManager V Created new loader LoaderInfo{405a2298 #78 : CursorLoader{405a22e0}} 
     DummyApp D DataFragment.onCreate 
     DummyApp D DataFragment.onActivityCreated 
     DummyApp D ReportFragment.onCreate 
LoaderManager V initLoader in LoaderManager{405a19d0 in DummyActivity{4059ee98}}: args=null 
LoaderManager V Re-using existing loader LoaderInfo{405a2298 #78 : CursorLoader{405a22e0}} 
     DummyApp D SpecificActionReportFragment.onCreate 
     DummyApp D SpecificActionReportFragment.onActivityCreated 
LoaderManager V Starting in LoaderManager{405a19d0 in DummyActivity{4059ee98}} 
LoaderManager V Starting: LoaderInfo{405a2298 #78 : CursorLoader{405a22e0}} 
DummyProvider D query called 
DummyProvider D […]  
DummyProvider D [end of query] 
LoaderManager V onLoadComplete: LoaderInfo{405a2298 #78 : CursorLoader{405a22e0}} 
LoaderManager V onLoadFinished in CursorLoader{405a22e0 id=78}: CursorWrapperInner{405afb20} 
     DummyApp D ReportFragment.onLoadFinished 
     DummyApp D ReportFragment.displayActionReport 
     DummyApp D DummyActivity.setReportViewsVisibility 
     DummyApp D ReportFragment.setSaveReportImageViewVisibility 

Los dos fragmentos se agregan a partir del método DummyActivity onCreate (diferente del caso de uso descrito, pero que no cambia nada a la cuestión que estamos trabajando) Desafortunadamente, el cargador es reasignado al último fragmento que lo llama (aquí ReportFragment) ... y DataFragment.onLoadFinished nunca se llama. Como consecuencia, ReportFragment se ve bien pero DataFragment no está actualizado ya que se llama a la actualización desde el onLoadFinished de esta clase.

Supongo que hay una llamada de anulación de registro subyacente y luego una llamada de registro en el CursorLoader.

Continuará ...

+0

¡Gracias por la respuesta! He estado haciendo algunas cosas con iOS, pero debería tener tiempo para jugar y terminar de responder esta pregunta en una semana más o menos. Informará de nuevo! :) – num1

+0

Voy a trabajar en eso también los próximos días porque mis compañeros de trabajo están esperando. – Renaud

+0

Eventualmente optimizaré mi ContentProvider. Lamento no merecer el punto de bonificación ...;) – Renaud

0

Sí. Funcionó para mí Tengo 3 Fragmentos diferentes en un Cajón de navegación donde se llenan los mismos datos en diferentes ListViews. (Todos los fragmentos son parte de la MISMA actividad).

Mi AsyncTaskLoader:

public class MyTaskLoader extends AsyncTaskLoader<HashMap<String, Integer>> { 

public MyTaskLoader(Context context) { 
    super(context); 
} 

@Override 
public HashMap<String, Integer> loadInBackground() { 
... 
return hashMap; 
} 

... 
} 

use el cargador de Id misma en todos los fragmentos.

Fragment1:

public class Fragment1 extends BaseFragment implements LoaderManager.LoaderCallbacks<HashMap<String, Integer>> { 
@Override 
public void onCreate(Bundle savedInstanceState) { 

//initialize adapter 

getActivity().getSupportLoaderManager().initLoader(0, null, this); 

} 

@Override 
public Loader<HashMap<String, Integer>> onCreateLoader(int arg0, Bundle arg1) { 
    // TODO Auto-generated method stub 

    return new MyTaskLoader(getActivity()); 
} 

@Override 
public void onLoadFinished(Loader<HashMap<String, Integer>> arg0, 
     HashMap<String, Integer> data) { 
    // TODO Auto-generated method stub 

    listAdapter.setData(data.keySet()); 

} 

@Override 
public void onLoaderReset(Loader<HashMap<String, Integer>> arg0) { 
    // TODO Auto-generated method stub 

    listAdapter.setData(null); 
} 
} 

utilizar el mismo ID de Fragment2:

public class Fragment2 extends BaseFragment implements LoaderManager.LoaderCallbacks<HashMap<String, Integer>> { 
@Override 
public void onCreate(Bundle savedInstanceState) { 

//initialize adapter 

getActivity().getSupportLoaderManager().initLoader(0, null, this); 

} 

@Override 
public Loader<HashMap<String, Integer>> onCreateLoader(int arg0, Bundle arg1) { 
    // TODO Auto-generated method stub 

    return new MyTaskLoader(getActivity()); 
} 

@Override 
public void onLoadFinished(Loader<HashMap<String, Integer>> arg0, 
     HashMap<String, Integer> data) { 
    // TODO Auto-generated method stub 

    listAdapter.setData(data.keySet()); 

} 

@Override 
public void onLoaderReset(Loader<HashMap<String, Integer>> arg0) { 
    // TODO Auto-generated method stub 

    listAdapter.setData(null); 
} 
} 

El adaptador debe ser inicializado antes de inicializar el cargador. Funciona hasta el momento. Pero, ¿es esta la manera correcta? ¿Existe un método mejor para usar un cargador común para múltiples Fragmentos?

Cuestiones relacionadas