Ricerca…


introduzione

Loader è una buona scelta per prevenire perdite di memoria se si desidera caricare i dati in background quando viene chiamato il metodo oncreate. Ad esempio, quando eseguiamo Asynctask nel metodo oncreate e ruotiamo lo schermo in modo da ricreare l'attività che eseguirà di nuovo un altro AsyncTask, quindi probabilmente due Asyntask in esecuzione in parallelo piuttosto che come loader che continuerà il processo in background eseguito in precedenza.

Parametri

Classe Descrizione
LoaderManager Una classe astratta associata ad un attività o frammento per la gestione di una o più istanze Loader.
LoaderManager.LoaderCallbacks Un'interfaccia di callback per un client per interagire con LoaderManager.
caricatore Una classe astratta che esegue il caricamento asincrono dei dati.
AsyncTaskLoader Caricatore astratto che fornisce un AsyncTask per eseguire il lavoro.
CursorLoader Una sottoclasse di AsyncTaskLoader che interroga ContentResolver e restituisce un Cursore.

Osservazioni

Introdotto in Android 3.0, i caricatori semplificano il caricamento asincrono dei dati in un'attività o in un frammento. I caricatori hanno queste caratteristiche:

  • Sono disponibili per ogni attività e frammento .
  • Forniscono il caricamento asincrono dei dati.
  • Monitorano la fonte dei loro dati e forniscono nuovi risultati quando il contenuto cambia.
  • Si riconnettono automaticamente al cursore dell'ultimo caricatore quando vengono ricreati dopo una modifica della configurazione. Quindi, non hanno bisogno di ri-interrogare i loro dati.

Quando non usare i caricatori

Non è necessario utilizzare Caricatori se è necessario completare le attività in background. Android distrugge i caricatori insieme alle attività / ai frammenti a cui appartengono. Se si desidera eseguire alcune attività, che devono essere eseguite fino al completamento, non utilizzare Caricatori. Dovresti invece usare i servizi per questo genere di cose.

AsyncTaskLoader di base

AsyncTaskLoader è un programma di Loader astratto che fornisce un AsyncTask per eseguire il lavoro.

Ecco alcune implementazioni di base:

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();
    }
}

In genere Loader viene inizializzato all'interno del metodo onCreate() dell'attività o all'interno di onActivityCreated() del frammento. Inoltre, solitamente l'attività o il frammento implementa LoaderManager.LoaderCallbacks interfaccia 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) {
    }
}

In questo esempio, quando il caricatore è completato, verrà mostrato un brindisi con il risultato.

AsyncTaskLoader con cache

È buona norma memorizzare nella cache i risultati caricati per evitare il caricamento multiplo degli stessi dati.
Per invalidare la cache onContentChanged() dovrebbe essere chiamato. Se il loader è già stato avviato, verrà chiamato forceLoad() , altrimenti (se il caricatore è in stato di arresto) il caricatore sarà in grado di comprendere la modifica del contenuto con il controllo takeContentChanged() .

Nota: onContentChanged() deve essere chiamato dal thread principale del processo.

Javadocs dice di takeContentChanged ():

Prendi il flag corrente per indicare se il contenuto del caricatore è stato modificato mentre era fermo. In tal caso, viene restituito true e la bandiera viene cancellata.

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
    }
}

Ricaricamento

Per invalidare i vecchi dati e riavviare il caricatore esistente è possibile utilizzare il metodo restartLoader() :

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

Passa i parametri usando un pacchetto

Puoi passare i parametri per Bundle:

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

Ottieni il valore in 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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow