web-dev-qa-db-fra.com

Exemple de base AsyncTaskLoader. (Android)

J'utilise un chargeur dans mon application et, en fonction du résultat de la requête que j'effectue sur COntacts à l'aide de ce chargeur, j'effectue des calculs et les stocke dans une base de données SQLite. Je souhaite que cette opération soit asynchrone, mais je ne comprends pas bien utiliser une tâche asynchrone, car j'ai de nombreux types de données à renvoyer ou dois-je utiliser un simple gestionnaire ou un AsyncTaskLoader; Chargeurs J'ai essayé de chercher des exemples d'AsyncTaskLoader, mais il me semble que la science de la fusée, un exemple fonctionnel simple et fondamental de l'un des trois dans le contexte de mon scénario serait beaucoup utile. 

21
Skynet

Si vous souhaitez utiliser AsyncTaskLoader, voici un bel exemple pour vous.

EDIT: J'ai décidé de faire une solution plus simple (basée sur ce repo ):

public abstract class AsyncTaskLoaderEx<T> extends AsyncTaskLoader<T> {
    private static final AtomicInteger sCurrentUniqueId = new AtomicInteger(0);
    private T mData;
    public boolean hasResult = false;

    public static int getNewUniqueLoaderId() {
        return sCurrentUniqueId.getAndIncrement();
    }

    public AsyncTaskLoaderEx(final Context context) {
        super(context);
        onContentChanged();
    }

    @Override
    protected void onStartLoading() {
        if (takeContentChanged())
            forceLoad();
        //this part should be removed from support library 27.1.0 :
        //else if (hasResult)
        //    deliverResult(mData);
    }

    @Override
    public void deliverResult(final T data) {
        mData = data;
        hasResult = true;
        super.deliverResult(data);
    }

    @Override
    protected void onReset() {
        super.onReset();
        onStopLoading();
        if (hasResult) {
            onReleaseResources(mData);
            mData = null;
            hasResult = false;
        }
    }

    protected void onReleaseResources(T data) {
        //nothing to do.
    }

    public T getResult() {
        return mData;
    }
}

Usage:

dans votre activité:

        getSupportLoaderManager().initLoader(TASK_ID, TASK_BUNDLE, new LoaderManager.LoaderCallbacks<Bitmap>() {
            @Override
            public Loader<Bitmap> onCreateLoader(final int id, final Bundle args) {
                return new ImageLoadingTask(MainActivity.this);
            }

            @Override
            public void onLoadFinished(final Loader<Bitmap> loader, final Bitmap result) {
                if (result == null)
                    return;
                //TODO use result
            }

            @Override
            public void onLoaderReset(final Loader<Bitmap> loader) {
            }
        });

classe statique interne ou classe normale:

private static class ImageLoadingTask extends AsyncTaskLoaderEx<Bitmap> {

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

    @Override
    public Bitmap loadInBackground() {
        //TODO load and return bitmap
    }
}

Mise à jour: à partir de la bibliothèque de support 27.1.0, les choses ont un peu changé (lien ici ):

Dans la version 27.1.0, onStartLoading () est appelée à chaque fois que Activity a démarré. Puisque vous appelez deliverResult () dans onStartLoading (), vous déclencher onLoadFinished (). Cela fonctionne comme prévu.

Vous devez supprimer votre appel à deliverResult () de onStartLoading () comme il n'est pas nécessaire (les chargeurs fournissent déjà des résultats calculés dans loadInBackground () sans aucun travail supplémentaire de votre part).

J'ai mis à jour le code ci-dessus pour ce changement.

29
android developer

Depuis Honeycomb et la v4 Compatibility Library, il est possible d’utiliser AsyncTaskLoader. D'après ce que j'ai compris, la AsyncTaskLoader peut survivre grâce aux changements de configuration tels que les retournements d'écran. Mais en utilisant AsyncTask, vous pouvez vous embrouiller avec les changements de configuration.

Informations clés: AsyncTaskLoader est une sous-classe de Loader. Cette classe remplit la même fonction que AsyncTask, mais un peu mieux peut aussi être utile pour gérer les modifications de configuration (orientation de l’écran).

Vous trouverez ici un très bon exemple et une explication . http://www.javacodegeeks.com/2013/01/Android-loaders-versus-asynctask.html

Google a un très bon exemple directement dans les documents API . Android Design Patterns fournit plus de détails et le raisonnement derrière Loaders.

Ce tutoriel va certainement vous aider. http://www.javacodegeeks.com/2013/08/Android-custom-loader-to-load-data-directly-from-sqlite-database.html

12
DeepakPanwar

Voici un tutoriel pas à pas pour implémenter AsyncTaskLoader. ou consultez ce même article sur Moyen

  1. Implémentez LoaderManager.LoaderCallbacks<String> sur MainActivity et créez un static int pour identifier de manière unique votre chargeur et créez une clé String pour transmettre l'URL de chaîne à votre chargeur.

    public class MainActivity extends AppCompatActivity 
                 implements LoaderManager.LoaderCallbacks<String>{
        public static final int OPERATION_SEARCH_LOADER = 22;
        public static final String OPERATION_QUERY_URL_EXTRA = "query";
    //...}
    
  2. Remplacer les fonctions onCreateLoader, onLoadFinishedet onLoaderReset dans MainActivity

    @Override
    public Loader<String> onCreateLoader(int id, final Bundle args) {
        //Here we will initiate AsyncTaskLoader
        return null;
    }
    
    @Override
    public void onLoadFinished(Loader<String> loader, String operationResult) {
        //Think of this as AsyncTask onPostExecute method, the result from onCreateLoader will be available in operationResult variable and here you can update UI with the data fetched.
        Log.d("MAINACTIVITY","result : "+ operationResult);
    }
    
    @Override
    public void onLoaderReset(Loader<String> loader) {
        //Don't bother about it, Android Studio will override it for you
    }
    
  3. inside onCreateLoader() renvoie un nouveau AsyncTaskLoader<String> en tant que classe interne anonyme avec this en tant que paramètre du constructeur et remplace loadInBackground & onStartLoading dans anonymous classe interne

    @Override
    public Loader<String> onCreateLoader(int id, final Bundle args) {
        return new AsyncTaskLoader<String>(this) {
            @Override
            public String loadInBackground() {
                //Think of this as AsyncTask doInBackground() method, here you will actually initiate Network call
                return null;
            }
    
            @Override
            protected void onStartLoading() {
               //Think of this as AsyncTask onPreExecute() method,start your progress bar,and at the end call forceLoad(); 
               forceLoad();
            }
        };
    }
    
  4. Dans loadInBackground, effectuez un appel réseau à l'aide de HTTPUrlConnection ou OKHttp ou de tout ce que vous utilisez.

     @Override
        public String loadInBackground() {
            String url = args.getString(OPERATION_QUERY_URL_EXTRA);//This is a url in string form 
            if (url!=null&&"".equals(url)) {
                return null;//if url is null, return
            }
            String operationResult="";
            try {
                operationResult = NetworkUtils.getResponseFromHttpUrl(url);//This just create a HTTPUrlConnection and return result in strings
            } catch (IOException e) {
                e.printStackTrace();
            }
            return operationResult;
        }
    
  5. Dans onCreate, initialisez le chargeur avec OPERATION_SEARCH_LOADER comme ID, null pour l'ensemble, et ceci pour le contexte.

    getSupportLoaderManager().initLoader(OPERATION_SEARCH_LOADER, null, this);
    
  6. Appelez maintenant cette méthode, quand et où vous voulez déclencher le chargeur

    private void makeOperationSearchQuery(String url) {
    
        // Create a bundle called queryBundle
        Bundle queryBundle = new Bundle();
        // Use putString with OPERATION_QUERY_URL_EXTRA as the key and the String value of the URL as the value
        queryBundle.putString(OPERATION_QUERY_URL_EXTRA,url);
        // Call getSupportLoaderManager and store it in a LoaderManager variable
        LoaderManager loaderManager = getSupportLoaderManager();
        // Get our Loader by calling getLoader and passing the ID we specified
        Loader<String> loader = loaderManager.getLoader(OPERATION_SEARCH_LOADER);
        // If the Loader was null, initialize it. Else, restart it.
        if(loader==null){
            loaderManager.initLoader(OPERATION_SEARCH_LOADER, queryBundle, this);
        }else{
            loaderManager.restartLoader(OPERATION_SEARCH_LOADER, queryBundle, this);
        }
    }
    

Walla, vous avez terminé, juste pour vous rappeler que NetworkUtils.getResponseFromHttpUrl(url); est ma fonction personnalisée qui consiste à convertir chaîne en chaîne URL qui à son tour servait à créer HTTPUrlConnection

9
L-X

J'aime ce bref exemple AsyncTask et AsyncTaskLoader .

class FooLoader extends AsyncTaskLoader {
   public FooLoader(Context context, Bundle args) {
      super(context);
      // do some initializations here
   }
   public String loadInBackground() {
      String result = "";
      // ...
      // do long running tasks here
      // ...
      return result;
   }
} 


class FooLoaderClient implements LoaderManager.LoaderCallbacks {
   Activity context;
   // to be used for support library:
   // FragmentActivity context2;
   public Loader onCreateLoader(int id, Bundle args) {
      // init loader depending on id
      return new FooLoader(context, args);
   }
   public void onLoadFinished(Loader loader, String data) {
      // ...
      // update UI here
      //
   }
   public void onLoaderReset(Loader loader) {
      // ...
   }
   public void useLoader() {
      Bundle args = new Bundle();
      // ...
      // fill in args
      // ...
      Loader loader = 
         context.getLoaderManager().initLoader(0, args, this);
      // with support library: 
      // Loader loader = 
      //    context2.getSupportLoaderManager().initLoader(0, args, this);
      // call forceLoad() to start processing
      loader.forceLoad();
   }
}
7
JDOaktown

Simplifier fort, peut-être

  private void loadContent() {
    getLoaderManager().initLoader(1000, new Bundle(), 
      new LoaderManager.LoaderCallbacks<List<String>>() {

      @Override
      public Loader<List<String>> onCreateLoader(int id, Bundle args) {
        return new AsyncTaskLoader<List<String>>(MainActivity.this.getApplicationContext()) {

          @Override
          public List<String> loadInBackground() {
            Log.i("B", "Load background data ");
            ArrayList<String> data = new ArrayList<>();
            for (int i = 0; i < 5000; i++) {
              data.add("Data." + i + " " + System.currentTimeMillis());
            }
            try {
              Thread.sleep(5000);
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
            return data;
          }
        };
      }

      @Override
      public void onLoadFinished(Loader<List<String>> loader, List<String> data) {
        Log.i("B", "Here are your data loaded" + data);
        if (!loader.isAbandoned()) {
          mAdapter.setData(data); // Read also about RecyclerView
        }
      }

      @Override
      public void onLoaderReset(Loader<List<String>> loader) {
        Log.i("B", "Loader reset");
      }
    }).forceLoad();
  }

  @Override
  protected void onDestroy() {
    // Abandon the loader so that it should not attempt to modify already dead GUI component
    getLoaderManager().getLoader(1000).abandon();
    super.onDestroy();
  }

Faites cette partie de votre activité. L'exemple simule un délai, mais rend les nouvelles entrées faciles à reconnaître car elles porteront le suffixe d'horodatage différent. Naturellement, vous avez également besoin de RecyclerView pour afficher les données, la réponse à cette question semble très bonne.

Le chargeur dans cet exemple est la classe interne qui conserve la référence à l'activité parent. Il doit s'agir d'une classe statique externe sans cette référence en production.

1
h22

Je préfère utiliser Bolts-Android. c'est très facile.

https://github.com/BoltsFramework/Bolts-Android

Task.callInBackground(new Callable<Void>() {
  public Void call() {
    // Do a bunch of stuff.
  }
}).continueWith(...);
0
ray pixar