2012-09-03 20 views
36

Odio la clase interna.Android: ¿Cómo actualizar una interfaz de usuario de AsyncTask si AsyncTask está en una clase separada?

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

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

necesito tarea asíncrona actualiza un Textview de la actividad principal.

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

Pero, ¿cómo de una, independiente, tarea externa asíncrono?

ACTUALIZACIÓN: Esto parece de trabajo:

En acitivty que llamo la tarea

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

En el constructor ive

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

donde depuración era un campo privado de AsyncTask.

Así onProgressUpdate puedo

debug.append(text); 

Gracias por todos ustedes sugerencias

+0

¿Quiere decir que en otra clase, quiere acceder a la IU? –

+0

Sí. Necesito actualizar un TextView de AsyncTask. – realtebo

+0

Puede pasar Contexto en su constructor y al convertirlo a su ActivityClass, puede cambiar textView utilizando el método runOnUIThread. –

Respuesta

31

EDITAR que editó la respuesta a utilizar WeakReference


AsyncTask es siempre la clase separada de Activity, pero sospecho que quiere decir que está en archivo diferente que el archivo de clase de actividad, por lo que no puede beneficiarse de siendo la clase interna de la actividad. Basta con pasar contexto de actividad como argumento para su asíncrono de tareas (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 usar cuando lo necesite (recuerde no usar durante doInBackground()) es decir, de modo que cuando usted normalmente llamar

int id = findViewById(...) 

en AsyncTask se llama a decir

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

Tenga en cuenta que nuestra Activity puede desaparecer mientras doInBackground() está en curso (por lo que el refere nce returned puede convertirse en null), pero al usar WeakReference no evitamos que GC lo recopile (y pierda memoria) y como Activity se ha ido, por lo general no tiene sentido intentar actualizar su estado (aún así, dependiendo de su lógica, puede querer para hacer algo como cambiar el estado interno o actualizar DB, pero se debe omitir el toque de UI).

+2

Si realiza esta ruta, es mejor mantener la referencia de actividad como WeakReference en lugar de simplemente Activity. IMO. – newbyca

+0

¿Qué es "WeakReference"? – realtebo

+0

WebnetMobile.com, ah ok, no estaba seguro, es bueno saberlo. @realtebo, http://developer.android.com/reference/java/lang/ref/WeakReference.html – newbyca

3

Sólo tiene que pasar el contexto (actividad o lo que sea) a su AsyncTask en un constructor y luego en onSuccess o llame al onProgressUpdate lo que sea necesario en el contexto.

2

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

En Clase de actividad: pública updateTextView static void() {

// su código aquí }

En AynckTask llamada clase esta función.

+0

perfecto. ¡Gracias! – hoss

3

Escribí una pequeña extensión a AsyncTask para este tipo de escenario. Que le permite mantener su AsyncTask en una clase separada, sino que también le da 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 se extienden ListenableAsyncTask en lugar de AsyncTask. Luego, en su código de UI, cree una instancia concreta y establezca listenWith (...).

2

La pregunta ya ha sido contestada, siendo la publicación im cómo debe hacerse supongo ..

clase Mainactivity

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 asíncrona

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 
    } 
} 
1
/** 
    * 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"); 
     } 
    } 

// lugar este código dentro de la clase de actividad y también declarar la actualización de Vista de Texto estático

public static void UpdateTextViewData(String tvData) 
{ 
    tv.setText(tvData); 
} 
18

medio de la interfaz 1) Crear una interfaz

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

2) 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 el archivo AsyncTask y método de interfaz de llamada como a continuación.

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án a cabo la tarea realizada por AsyncTask y conseguirá "número" como un parámetro, devuelto por doInBackground() {return "";}.

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

Un caso extremo de recordar: Asegúrese de pasar this, es decir, que el contexto de la actividad actual de AsyncTask y no crear otra instancia de su actividad, de lo contrario su Activity serán destruidas y se crea uno nuevo.

+0

Esto tal vez en el primer vistazo, no puede manejar múltiples 'AsyncTask' generales en una actividad. – zionpi

+0

Esta es una buena solución. La implementación de una interfaz relajará el acoplamiento y se recomienda en este video para desarrolladores de Android: https://www.youtube.com/watch?v=jtlRNNhane0&index=4&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE. –

Cuestiones relacionadas