thread example android android-asynctask android-handler

thread - android handler example



Ejemplo básico de AsyncTaskLoader.(Androide) (6)

Estoy usando un Loader en mi aplicación y, en función del resultado que obtengo de la consulta que realizo en COntacts utilizando este Loader, realizo algunos cálculos y los vuelvo a almacenar en un DB de Sqlite. Quiero que esta operación sea asincrónica, sin embargo, estoy confundido al usar una tarea asíncrona, ya que tengo muchos tipos de datos diferentes que devolver o si debo usar un controlador simple o un AsyncTaskLoader, quiero que sea simple ya que soy nuevo en Los cargadores Intenté buscar ejemplos de AsyncTaskLoader, pero parece una ciencia espacial, un ejemplo funcional simple y básico de cualquiera de los tres en el contexto de mi escenario sería muy útil.


Aquí hay un tutorial paso a paso para implementar AsyncTaskLoader . o echa un vistazo a este mismo artículo en Medium

  1. Implemente LoaderManager.LoaderCallbacks<String> en MainActivity y cree un static int para identificar de forma única su cargador y crear una clave de cadena para pasar la URL de cadena a su cargador

    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. Reemplace las onCreateLoader , onLoadFinished y onLoaderReset dentro de 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. dentro de onCreateLoader() devuelve un nuevo AsyncTaskLoader<String> como una clase interna anónima con this como el parámetro del constructor y reemplaza loadInBackground & onStartLoading dentro de la clase interna anónima

    @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. Inside loadInBackground realiza una llamada de red utilizando HTTPUrlConnection o OKHttp o cualquier cosa que use.

    @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. Inside onCreate inicializa el cargador con OPERATION_SEARCH_LOADER como ID, nulo para el paquete, y esto para el contexto

    getSupportLoaderManager().initLoader(OPERATION_SEARCH_LOADER, null, this);

  6. Ahora llame a este método, cuando y donde quiera que desee activar el cargador

    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, has terminado, solo para recordarte NetworkUtils.getResponseFromHttpUrl(url); es mi función personalizada la que toma la cadena la convierte en una URL que a su vez se usa para crear HTTPUrlConnection


Desde Honeycomb y la biblioteca de compatibilidad v4 es posible usar AsyncTaskLoader . Por lo que entiendo, el AsyncTaskLoader puede sobrevivir a través de cambios en la configuración, como los cambios de pantalla. Pero al usar AsyncTask puede desordenar los cambios de configuración.

Información clave: AsyncTaskLoader es subclase de Loader . Esta clase realiza la misma función que AsyncTask, pero un poco mejor, también puede ser útil para manejar los cambios de configuración (orientación de la pantalla).

Un muy buen ejemplo y explicación se da aquí. http://www.javacodegeeks.com/2013/01/android-loaders-versus-asynctask.html

Google tiene un ejemplo bastante bueno directamente en los documentos API. Los patrones de diseño de Android proporcionan más detalles y el razonamiento detrás de los cargadores.

Este tutorial definitivamente te ayudará. http://www.javacodegeeks.com/2013/08/android-custom-loader-to-load-data-directly-from-sqlite-database.html


Me gusta este breve ejemplo de AsyncTask y 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(); } }



Si desea utilizar AsyncTaskLoader, here''s una buena muestra para usted.

EDITAR: He decidido hacer una solución más simple (basada en este repositorio ):

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

Uso:

en tu actividad:

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

Clase estática interna, o una clase normal:

private static class ImageLoadingTask extends AsyncTaskLoaderEx<Bitmap> { public ImageLoadingTask (Context context) { super(context); } @Override public Bitmap loadInBackground() { //TODO load and return bitmap } }

Actualización: a partir de la biblioteca de soporte 27.1.0, las cosas cambiaron un poco (enlace here ):

En la versión 27.1.0, se llama a onStartLoading () cada vez que se inicia la Actividad. Como llama a deliverResult () en onStartLoading (), desencadena onLoadFinished (). Esto está funcionando según lo previsto.

Debe eliminar su llamada a deliverResult () de onStartLoading () ya que no es necesario (los cargadores ya entregan los resultados calculados en loadInBackground () sin ningún trabajo adicional necesario de su parte).

He actualizado el código anterior para este cambio.


Simplificando duro, tal vez

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

Haga esta parte de su actividad. La muestra simula el retraso, pero hace que las nuevas entradas sean fáciles de reconocer porque tendrán el sufijo de marca de tiempo diferente. Por supuesto, también necesita RecyclerView para mostrar los datos, la respuesta a esta pregunta parece muy buena.

El cargador en este ejemplo es la clase interna que mantiene la referencia a la actividad principal. Debe ser una clase estática externa sin tal referencia en producción.