Android: ¿Cómo actualizar una interfaz de usuario desde AsyncTask si AsyncTask está en una clase separada?


Odio la clase interna.

Tengo una actividad principal que lanza una AsyncTask 'de corta duración'.

AsyncTask es en un archivo separado , no es una clase interna de actividad principal

Necesito que la tarea asincrónica actualice un TextView de la actividad principal.

Sé que puedo actualizar un TextView desde onProgressUpdate, si AsyncTask es una clase interna

Pero, ¿cómo desde una tarea externa, independiente y asíncrona ?

ACTUALIZACIÓN: Esto parece funcionar:

En acitivty llamo el tarea

backgroundTask = new BackgroundTask(this);
backgroundTask.execute();

En el constructor he

public BackgroundTask(Activity myContext)
{
    debug = (TextView) myContext.findViewById(R.id.debugText);
}

Donde debug era un campo privado de AsyncTask.

Así que onProgressUpdate puedo

debug.append(text);

Gracias por todas sus sugerencias

Author: realtebo, 2012-09-03

7 answers

EDIT Edité la respuesta para usar WeakReference


AsyncTask siempre es una clase separada de Activity, pero sospecho que quiere decir que está en un archivo diferente al archivo de su clase de actividad, por lo que no puede beneficiarse de ser la clase interna de la actividad. Simplemente pase el contexto de Actividad como argumento a su Tarea Asíncrona (es decir, a su constructor)

class MyAsyncTask extends AsyncTask<URL, Integer, Long> {

    WeakReference<Activity> mWeakActivity;

    public MyAsyncTask(Activity activity) {
       mWeakActivity = new WeakReference<Activity>(activity);
    }

 ...

Y úselo cuando lo necesite (recuerde NO usarlo durante doInBackground()), es decir, cuando normalmente llamaría

int id = findViewById(...)

En AsyncTask usted llama es decir,

Activity activity = mWeakActivity.get();
if (activity != null) {
   int id = activity.findViewById(...);
}

Tenga en cuenta que nuestro Activity puede desaparecer mientras doInBackground() está en progreso (por lo que la referencia devuelta puede convertirse en null), pero mediante el uso de WeakReference no impedimos que GC lo recopile (y filtre memoria) y como la actividad se ha ido, por lo general no tiene sentido siquiera intentar actualizarlo (aún así, dependiendo de su lógica, es posible que desee hacer algo como cambiar el estado interno o actualizar la base de datos, pero se debe omitir tocar la interfaz de usuario).

 35
Author: Marcin Orlowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-15 12:25:28

Usando Interfaz 1) Crear una interfaz

public interface OnDataSendToActivity {
    public void sendData(String str);
}

2) Lo implementa en su Actividad

public class MainActivity extends Activity implements OnDataSendToActivity{

     @Override
     protected void onCreate(Bundle savedInstanceState) {
          new AsyncTest(this).execute(new String[]{"AnyData"}); // start your task
     }

     @Override
     public void sendData(String str) {
         // TODO Auto-generated method stub

     }

}

3) Crear constructor en AsyncTask (Actividad actividad){} Registre su interfaz en un archivo AsyncTask y llame al método de interfaz de la siguiente manera.

public class AsyncTest extends AsyncTask<String, Integer, String> {

    OnDataSendToActivity dataSendToActivity;
    public AsyncTest(Activity activity){
        dataSendToActivity = (OnDataSendToActivity)activity;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        dataSendToActivity.sendData(result);
    }

}

Aquí, su onPostExecute llamará después de toda la tarea realizada por AsyncTask y obtendrá " resultado" como parámetro, devuelto por doInBackground () {return"";}.

Mientras "dataSendToActivity.sendData (result); " llamará método anulado de la actividad " public void sendData (String str) {}".

Un caso de borde para recordar: Asegúrese de pasar this, es decir, el contexto de su actividad actual a AsyncTask y no crear otra instancia de su actividad, de lo contrario su Activity se destruirá y se creará una nueva.

 18
Author: Ams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-12 14:21:31

Haga una función estática en su clase activity pasando contexto en ella para actualizar su vista de texto y luego llame a esta función en su clase AsynkTask para actualizar.

En la clase de actividad: public static void updateTextView () {

/ / su código aquí }

En la clase AynckTask llame a esta función.

 4
Author: pyus13,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-03 18:53:31

Simplemente pase el contexto (actividad o lo que sea) a su AsyncTask en un constructor y luego enuccuccess o onProgressUpdate llame a lo que necesite en el contexto.

 3
Author: Manfred Moser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-03 18:41:50

Escribí una pequeña extensión para AsyncTask para este tipo de escenario. Le permite mantener su AsyncTask en una clase separada, pero también le da un acceso conveniente a la finalización de las tareas:

public abstract class ListenableAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result>{

    @Override
    protected final void onPostExecute(Result result) {
        notifyListenerOnPostExecute(result);
    }

    private AsyncTaskListener<Result> mListener;
    public interface AsyncTaskListener<Result>{
        public void onPostExecute(Result result);
    }
    public void listenWith(AsyncTaskListener<Result> l){
        mListener = l;
    }
    private void notifyListenerOnPostExecute(Result result){
        if(mListener != null)
            mListener.onPostExecute(result);
    }

}

Así que primero extiendes ListenableAsyncTask en lugar de AsyncTask. Luego, en tu código de interfaz de usuario, crea una instancia concreta y establece listenWith(...).

 3
Author: newbyca,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-03 18:54:54

La pregunta ya ha sido respondida, todavía estoy publicando cómo se debe hacer, supongo..

Clase de actividad principal

  public class MainActivity extends Activity implements OnClickListener
    {

        TextView Ctemp;

        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Ctemp = (TextView) findViewById(R.id.Ctemp);
            doConv = (Button) findViewById(R.id.doConv);
            doConv.setOnClickListener(this);
        }

        @Override
        public void onClick(View arg0) // The conversion to do
        {
            new asyncConvert(this).execute();
        }
    }

Ahora en la clase async

public class asyncConvert extends AsyncTask<Void, Void, String>
{
    SoapPrimitive response = null;
    Context context;

    public asyncConvert(Context callerclass)
    {
        contextGUI = callerclass;
    }
.
.
.
.
protected void onPostExecute(String result)
    {
        ((MainActivity) contextGUI).Ctemp.setText(result); // changing TextView
    }
}
 2
Author: Sujal Mandal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-15 18:51:32
    /**
     * Background Async Task to Load all product by making HTTP Request
     * */
     public  static class updateTExtviewAsyncTask extends AsyncTask<String, String, String> {

        Context context;
        ProgressDialog pDialog;
        String id, name;

        String state_id;

        //--- Constructor for getting network id from asking method

        public  updateTExtviewAsyncTask(Context context,String id,String city) 
        {
            context   = context;
            state_id  = id;
            city_name = city;
        }       
        /* *
         * Before starting background thread Show Progress Dialog
         * */
        @Override
        protected void onPreExecute() 
        {
            super.onPreExecute();
            pDialog = ProgressDialog.show(context, "","Please wait...", true, true);
            pDialog.show();

        }

        /**
         * getting All products from url
         * */
        protected String doInBackground(String... args) 
        {
            return null;
        }

        /**
         * After completing background task Dismiss the progress dialog
         * **/
            protected void onPostExecute(String file_url)  {

                     YourClass.UpdateTextViewData("Textview data");
        }
    }

/ / coloque este código dentro de su clase de actividad y también declare la actualización de textview static

    public static void  UpdateTextViewData(String tvData) 
{
   tv.setText(tvData);
}
 1
Author: Lucky Rana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-03 10:30:04