Buscar..


Introducción

El cargador es una buena opción para prevenir la pérdida de memoria si desea cargar datos en segundo plano cuando se llama al método oncreate. Por ejemplo, cuando ejecutamos Asynctask en el método oncreate y rotamos la pantalla, la actividad volverá a crear lo que ejecutará otra AsyncTask nuevamente, así que probablemente dos Asyntask se ejecuten en paralelo en lugar de un cargador similar que continuará el proceso en segundo plano que ejecutamos antes.

Parámetros

Clase Descripción
LoaderManager Una clase abstracta asociada con una Actividad o Fragmento para administrar una o más instancias de Loader.
LoaderManager.LoaderCallbacks Una interfaz de devolución de llamada para que un cliente interactúe con el LoaderManager.
Cargador Una clase abstracta que realiza la carga asíncrona de datos.
AsyncTaskLoader Cargador abstracto que proporciona una AsyncTask para hacer el trabajo.
CursorLoader Una subclase de AsyncTaskLoader que consulta el ContentResolver y devuelve un cursor.

Observaciones

Introducidos en Android 3.0, los cargadores facilitan la carga asincrónica de datos en una actividad o fragmento. Los cargadores tienen estas características:

  • Están disponibles para cada actividad y fragmento .
  • Proporcionan carga asíncrona de datos.
  • Supervisan la fuente de sus datos y entregan nuevos resultados cuando cambia el contenido.
  • Se vuelven a conectar automáticamente al cursor del último cargador cuando se recrean después de un cambio de configuración. Por lo tanto, no necesitan volver a consultar sus datos.

Cuando no usar cargadores

No debe usar los cargadores si necesita completar las tareas en segundo plano. Android destruye los cargadores junto con las actividades / fragmentos a los que pertenecen. Si desea realizar algunas tareas, que deben ejecutarse hasta su finalización, no use los cargadores. Deberías usar servicios para este tipo de cosas en su lugar.

AsyncTaskLoader básico

AsyncTaskLoader es un Loader abstracto que proporciona una AsyncTask para realizar el trabajo.

Aquí algunas implementaciones básicas:

final class BasicLoader extends AsyncTaskLoader<String> {

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

    @Override
    public String loadInBackground() {
        // Some work, e.g. load something from internet
        return "OK";
    }

    @Override
    public void deliverResult(String data) {
        if (isStarted()) {
            // Deliver result if loader is currently started
            super.deliverResult(data);
        }
    }

    @Override
    protected void onStartLoading() {
        // Start loading
        forceLoad();
    }

    @Override
    protected void onStopLoading() {
        cancelLoad();
    }

    @Override
    protected void onReset() {
        super.onReset();

        // Ensure the loader is stopped
        onStopLoading();
    }
}

Normalmente, Loader se inicializa dentro del método onCreate() la actividad, o dentro del onActivityCreated() del fragmento. También usualmente la actividad o el fragmento implementa la interfaz LoaderManager.LoaderCallbacks :

public class MainActivity extends Activity implements LoaderManager.LoaderCallbacks<String> {

    // Unique id for loader
    private static final int LDR_BASIC_ID = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Initialize loader; Some data can be passed as second param instead of Bundle.Empty
        getLoaderManager().initLoader(LDR_BASIC_ID, Bundle.EMPTY, this);
    }

    @Override
    public Loader<String> onCreateLoader(int id, Bundle args) {
        return new BasicLoader(this);
    }

    @Override
    public void onLoadFinished(Loader<String> loader, String data) {
        Toast.makeText(this, data, Toast.LENGTH_LONG).show();
    }

    @Override
    public void onLoaderReset(Loader<String> loader) {
    }
}

En este ejemplo, cuando se complete el cargador, se mostrará una tostada con el resultado.

AsyncTaskLoader con caché

Es una buena práctica almacenar en caché el resultado cargado para evitar la carga múltiple de los mismos datos.
Para invalidar la memoria caché, se debe llamar a onContentChanged() . Si el cargador ya se ha iniciado, se forceLoad() , de lo contrario (si el cargador está en estado detenido) el cargador podrá comprender el cambio de contenido con la takeContentChanged() .

Nota: se debe llamar a onContentChanged() desde el hilo principal del proceso.

Javadocs dice acerca de takeContentChanged ():

Tome la marca actual que indica si el contenido del cargador ha cambiado mientras se detuvo. Si es así, devuelve true y se borra la bandera.

public abstract class BaseLoader<T> extends AsyncTaskLoader<T> {

    // Cached result saved here
    private final AtomicReference<T> cache = new AtomicReference<>();

    public BaseLoader(@NonNull final Context context) {
        super(context);
    }

    @Override
    public final void deliverResult(final T data) {
        if (!isReset()) {
            // Save loaded result
            cache.set(data);
            if (isStarted()) {
                super.deliverResult(data);
            }
        }
    }

    @Override
    protected final void onStartLoading() {            
        // Register observers
        registerObserver();

        final T cached = cache.get();    
        // Start new loading if content changed in background
        // or if we never loaded any data
        if (takeContentChanged() || cached == null) {
            forceLoad();
        } else {
            deliverResult(cached);
        }
    }

    @Override
    public final void onStopLoading() {
        cancelLoad();
    }

    @Override
    protected final void onReset() {
        super.onReset();
        onStopLoading();
        // Clear cache and remove observers
        cache.set(null);
        unregisterObserver();
    }

    /* virtual */
    protected void registerObserver() {
        // Register observers here, call onContentChanged() to invalidate cache
    }

    /* virtual */
    protected void unregisterObserver() {
        // Remove observers
    }
}

Recarga

Para invalidar sus datos antiguos y reiniciar el cargador existente, puede usar el método restartLoader() :

private void reload() {
    getLoaderManager().reastartLoader(LOADER_ID, Bundle.EMPTY, this);
}

Pasar parámetros utilizando un paquete

Puedes pasar los parámetros por Bundle:

Bundle myBundle = new Bundle();
myBundle.putString(MY_KEY, myValue);

Obtenga el valor en onCreateLoader:

@Override
public Loader<String> onCreateLoader(int id, final Bundle args) {
    final String myParam = args.getString(MY_KEY);
    ...
}


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow