Pregunta Ejemplo AsyncTask Android


Estuve leyendo sobre AsyncTask, y probé el sencillo programa a continuación. pero no parece funcionar. ¿Cómo puedo hacer que funcione?

package com.test;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings.System;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.view.View.OnClickListener;

public class AsyncTaskActivity extends Activity {
    Button btn;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        btn = (Button) findViewById(R.id.button1);
        btn.setOnClickListener((OnClickListener) this);
    }

    public void onClick(View view){
        new LongOperation().execute("");
    }

    private class LongOperation extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... params) {
            for(int i=0;i<5;i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            TextView txt = (TextView) findViewById(R.id.output);
            txt.setText("Executed");
            return null;
        }

        @Override
        protected void onPostExecute(String result) {
        }

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected void onProgressUpdate(Void... values) {
        }
    }
}

Solo intento cambiar la etiqueta después de 5 segundos en el proceso de fondo.

Este es mi main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:orientation="vertical" >
    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:indeterminate="false"
        android:max="10"
        android:padding="10dip">
    </ProgressBar>
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start Progress" >
    </Button>
    <TextView android:id="@+id/output"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Replace"/>
</LinearLayout>

561
2018-03-12 17:09


origen


Respuestas:


Está bien, está intentando acceder a la GUI a través de otro hilo. Esto, en general, no es una buena práctica.

El AsyncTask ejecuta todo en doInBackground() dentro de otro hilo, que no tiene acceso a la GUI donde están tus vistas.

preExecute() y postExecute() le ofrece acceso a la GUI antes y después de que se produzca el levantamiento pesado en este nuevo hilo, incluso puede pasar el resultado de la operación larga a postExecute() para luego mostrar los resultados del procesamiento.

Vea estas líneas donde luego estará actualizando su TextView:

TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");

ponerlos en PostExecute()

A continuación, verá su texto TextView actualizado después de la doInBackground completa.

EDITAR: Noté que su oyente onClick no verifica qué Vista se ha seleccionado. Encuentro que la forma más fácil de hacer esto es a través de declaraciones de cambio. Tengo una clase completa editada a continuación con todas las sugerencias para evitar confusiones.

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings.System;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.view.View.OnClickListener;

public class AsyncTaskActivity extends Activity implements OnClickListener {

    Button btn;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btn = (Button) findViewById(R.id.button1);
        // because we implement OnClickListener we only have to pass "this"
        // (much easier)
        btn.setOnClickListener(this);
    }

    public void onClick(View view) {
        // detect the view that was "clicked"
        switch (view.getId()) {
        case R.id.button1:
            new LongOperation().execute("");
            break;
        }
    }

    private class LongOperation extends AsyncTask<String, Void, String> {

        @Override
        protected String doInBackground(String... params) {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.interrupted();
                }
            }
            return "Executed";
        }

        @Override
        protected void onPostExecute(String result) {
            TextView txt = (TextView) findViewById(R.id.output);
            txt.setText("Executed"); // txt.setText(result);
            // might want to change "executed" for the returned string passed
            // into onPostExecute() but that is upto you
        }

        @Override
        protected void onPreExecute() {}

        @Override
        protected void onProgressUpdate(Void... values) {}
    }
}

613
2018-03-12 17:12



Mi respuesta completa es aquí, pero aquí hay una imagen explicativa para complementar las otras respuestas en esta página. Para mí, entender dónde estaban todas las variables era la parte más confusa al principio.

enter image description here


633
2018-04-10 10:41



Estoy seguro de que se está ejecutando correctamente, pero estás tratando de cambiar los elementos de la interfaz de usuario en el hilo de fondo y eso no funcionará.

Revisa tu llamada y AsyncTask de la siguiente manera:

Clase de llamada

Nota: Yo personalmente sugiero usar onPostExecute() siempre que ejecute su subproceso AsyncTask y no en la clase que extiende AsyncTask. Creo que hace que el código sea más fácil de leer, especialmente si necesita AsyncTask en múltiples lugares manejando los resultados ligeramente diferente.

new LongThread()
{
    @Override public void onPostExecute(String result)
    {
        TextView txt = (TextView) findViewById(R.id.output);
        txt.setText(result);
    }
}.execute("");

Clase LongThread (extiende AsyncTask):

@Override
protected String doInBackground(String... params) {
    for(int i = 0; i < 5; i++) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    return "Executed";
}      

66
2018-03-12 17:15



Concepto y código aquí

He creado un ejemplo simple para usar AsyncTask de Android. Empieza con onPreExecute(), doInBackground(), publishProgress() y finalmente onProgressUpdate().

En este doInBackground () funciona como un hilo de fondo, mientras que otros funciona en el subproceso UI. No puede acceder a un elemento de IU en doInBackground (). La secuencia es la misma que he mencionado.

Sin embargo, si necesita actualizar cualquier widget de doInBackground usted puede publishProgress de doInBackground que llamará onProgressUpdate para actualizar tu widget de UI

class TestAsync extends AsyncTask<Void, Integer, String>
{
    String TAG = getClass().getSimpleName();

    protected void onPreExecute (){
        super.onPreExecute();
        Log.d(TAG + " PreExceute","On pre Exceute......");
    }

    protected String doInBackground(Void...arg0) {
        Log.d(TAG + " DoINBackGround","On doInBackground...");

        for(int i=0; i<10; i++){
            Integer in = new Integer(i);
            publishProgress(i);
        }
        return "You are at PostExecute";
    }

    protected void onProgressUpdate(Integer...a){
        super.onProgressUpdate(a);
        Log.d(TAG + " onProgressUpdate", "You are in progress update ... " + a[0]);
    }

    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        Log.d(TAG + " onPostExecute", "" + result);
    }
}

Llámalo así en tu actividad:

new TestAsync().execute();

Referencia del desarrollador aquí


47
2017-09-16 12:02



Mueva estas dos líneas:

TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");

de su AsyncTask's doInBackground método y ponerlos en el onPostExecute método. Tu AsyncTask debería verse algo como esto:

private class LongOperation extends AsyncTask<String, Void, String> {

    @Override
    protected String doInBackground(String... params) {
        try {
            Thread.sleep(5000); // no need for a loop
        } catch (InterruptedException e) {
            Log.e("LongOperation", "Interrupted", e);
            return "Interrupted";
        }
        return "Executed";
    }      

    @Override
    protected void onPostExecute(String result) {               
        TextView txt = (TextView) findViewById(R.id.output);
        txt.setText(result);
    }
}

13
2018-03-12 17:16



El ejemplo más corto para simplemente hacer algo de forma asíncrona:

class MyAsyncTask extends android.os.AsyncTask {
    @Override
    protected Object doInBackground(Object[] objects) {
        //do something asynchronously
        return null;
    }
}

Para ejecutarlo:

(new MyAsyncTask()).execute();

9
2018-06-12 11:17



Cuando se ejecuta una tarea asíncrona, la tarea pasa por 4 pasos:

  1. onPreExecute ()
  2. doInBackground (Params ...)
  3. onProgressUpdate (Progreso ...)
  4. onPostExecute (Resultado)

A continuación se muestra un ejemplo de demostración

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

y una vez que creó, una tarea se ejecuta de manera muy simple:

 new DownloadFilesTask().execute(url1, url2, url3);

Espero que esto ayude...


8
2018-01-23 11:20



Cuando está en el hilo de trabajo, no puede manipular directamente elementos de IU en Android.

Cuando usa AsyncTask, comprenda los métodos de devolución de llamada.

Por ejemplo:

public class MyAyncTask extends AsyncTask<Void, Void, Void>{

    @Override
    protected void onPreExecute() {
        // Here you can show progress bar or something on the similar lines.
        // Since you are in a UI thread here.
        super.onPreExecute();
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        // After completing execution of given task, control will return here.
        // Hence if you want to populate UI elements with fetched data, do it here.
    }

    @Override
    protected void onProgressUpdate(Void... values) {
        super.onProgressUpdate(values);
        // You can track you progress update here
    }

    @Override
    protected Void doInBackground(Void... params) {
        // Here you are in the worker thread and you are not allowed to access UI thread from here.
        // Here you can perform network operations or any heavy operations you want.
        return null;
    }
}

FYI: Para acceder al hilo de la interfaz de usuario de un hilo de trabajo, puede utilizar el método runOnUiThread () o el método de publicación en su vista.

Por ejemplo:

runOnUiThread(new Runnable() {
    textView.setText("something.");
});

or
    yourview.post(new Runnable() {
    yourview.setText("something");
});

Esto te ayudará a conocer las cosas mejor. Por lo tanto, en su caso, debe configurar su vista de texto en el método onPostExecute ().


5
2017-12-22 18:25



Antecedentes / Teoría

AsyncTask le permite ejecutar una tarea en un hilo de fondo, mientras publica resultados en el hilo de la interfaz de usuario.

El usuario siempre debe poder interactuar con la aplicación por lo que es importante para evitar bloquear el hilo principal (IU) con tareas tales como   descargar contenido de la web.

Es por eso que usamos un AsyncTask.

Ofrece una interfaz sencilla por envolviendo la cola de mensajes de la interfaz de usuario y el manejador de mensajes que le permiten enviar y procesar objetos ejecutables y mensajes de otros hilos.

Implementación

AsyncTask es una clase genérica (Se necesita tipos parametrizados en su constructor)

Utiliza estos tres tipos genéricos: 

Params - el tipo de parámetros enviados a la tarea en la ejecución.

Progress - el tipo de unidades de progreso publicadas durante el cálculo de fondo.

Result - el tipo del resultado del cálculo de fondo.

No todos los tipos son siempre utilizados por una tarea asincrónica. Para marcar un tipo como no utilizado, simplemente use el tipo Void:

private class MyTask extends AsyncTask<Void, Void, Void> { ... }

Estos tres parámetros corresponden a tres funciones principales puedes anular AsyncTask:

  • doInBackground(Params...)
  • onProgressUpdate(Progress...)
  • onPostExecute(Result)

Para ejecutar AsyncTask

llamada execute() con los parámetros que se enviarán a la tarea de fondo.

Lo que pasa

  1. En el hilo principal / UI, onPreExecute() se llama. (Para inicializar algo en este hilo, como mostrar una barra de progreso en la interfaz de usuario).

  2. En un hilo de fondo, doInBackground(Params...) se llama. (Los parámetros son los que pasan a la función Ejecutar).

    • Donde debe pasar la tarea de larga duración

    • Debe anular al menos doInBackground() para usar AsyncTask.

    • Llamada publishProgress(Progress...) para actualizar una pantalla de progreso en la interfaz de usuario mientras el cálculo de fondo aún se está ejecutando. (por ejemplo, animar una barra de progreso o mostrar registros en un campo de texto).

      • Esto causa onProgressUpdate() ser llamado.
  3. En el hilo de fondo, se devuelve un resultado doInBackground(). Esto desencadena el siguiente paso.

  4. En el hilo principal / UI, onPostExecute() llamado con el resultado devuelto.

Ejemplos

Usando de nuevo el ejemplo de la tarea de bloqueo para descargar algo de la web,

  • El ejemplo A descarga una imagen y lo muestra en un ImageView,
  • mientras El ejemplo B descarga algunos archivos.

Ejemplo A

los doInBackground() método descarga la imagen y la almacena en un objeto de tipo BitMap. los onPostExecute() método toma el mapa de bits y lo coloca en ImageView.

class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
    ImageView bitImage;

    public DownloadImageTask(ImageView bitImage) {
        this.bitImage = bitImage;
    }

    protected Bitmap doInBackground(String... urls) {
        String urldisplay = urls[0];
        Bitmap mBmp = null;
        try {
            InputStream in = new java.net.URL(urldisplay).openStream();
            mBmp = BitmapFactory.decodeStream(in);
        } catch (Exception e) {
            Log.e("Error", e.getMessage());
            e.printStackTrace();
        }
        return mBmp;
    }

    protected void onPostExecute(Bitmap result) {
        bitImage.setImageBitmap(result);
    }
}

Ejemplo B

 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

Ejemplo B ejecución

new DownloadFilesTask().execute(url1, url2, url3);

5
2017-09-17 16:20



Recomendaría hacerte la vida más fácil usando esta biblioteca para trabajos de fondo https://github.com/Arasthel/AsyncJobLibrary

Es así de simple ...

AsyncJob.doInBackground(new AsyncJob.OnBackgroundJob() {

    @Override
    public void doOnBackground() {
        startRecording();
    }
});

3
2017-11-29 23:39