2012-09-03 13 views
36

Odio la classe interiore.Android: come aggiornare un'interfaccia utente da AsyncTask se AsyncTask si trova in una classe separata?

Ho un'attività principale che avvia AsyncTask "a vita breve".

AsyncTask è in un file separato, non è una classe interna di attività principale

Ho bisogno compito asincrona aggiorna un textView da attività principale.

so di poter aggiornare un TextView da onProgressUpdate, se AsyncTask è una classe interna

Ma come da una, indipendente, task esterno asincrono?

UPDATE: Questo appare come lavoro:

In acitivty io chiamo il compito

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

Nel costruttore ho

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

dove il debug era un campo privato di AsyncTask.

Così onProgressUpdate posso

debug.append(text); 

Grazie per tutti voi suggerimenti

+0

Significa che in un'altra classe, si desidera accedere all'interfaccia utente? –

+0

Sì. Devo aggiornare un TextView da AsyncTask. – realtebo

+0

È possibile passare il contesto nel costruttore e con il cast nel ActivityClass, è possibile modificare textView utilizzando il metodo runOnUIThread. –

risposta

31

EDIT Ho modificato la risposta di utilizzare WeakReference


AsyncTask è sempre classe separata da Activity, ma ho il sospetto che dire che è nel file di diverso da quello del file di classe di attività, quindi non si può beneficiare di essere la classe interiore delle attività. È sufficiente passare contesto di attività come argomento di tuo Async Task (vale a dire a suo costruttore)

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

    WeakReference<Activity> mWeakActivity; 

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

... 

e utilizzare in caso di necessità (ricordate di non utilizzare per durante doInBackground()), cioè in modo che quando si sarebbe normalmente chiamare

int id = findViewById(...) 

in AsyncTask si chiama cioè

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

Nota che il nostro Activity possono essere andato mentre doInBackground() è in corso (in modo che il refere nce restituito può diventare null), ma utilizzando WeakReference non impediamo a GC di raccoglierlo (e di perdite di memoria) e man mano che Activity è sparito, di solito è inutile persino provare ad aggiornarlo (comunque, a seconda della logica che potresti desiderare fare qualcosa come cambiare lo stato interno o aggiornare il DB, ma toccare l'interfaccia utente deve essere saltato).

+2

Se si segue questo percorso, è meglio mantenere il riferimento attività come WeakReference anziché solo Attività. IMO. – newbyca

+0

Che cos'è "WeakReference"?! – realtebo

+0

WebnetMobile.com, ah ok, non ero sicuro, buono a sapersi. @realtebo, http://developer.android.com/reference/java/lang/ref/WeakReference.html – newbyca

3

Basta passare il contesto (attività o quant'altro) sul proprio AsyncTask in un costruttore e poi in onSuccess o chiamare onProgressUpdate qualunque cosa avete bisogno sul contesto.

2

Creare una funzione statica nella classe di attività passando il contesto in esso per aggiornare la visualizzazione del testo e quindi richiamare questa funzione nella classe AsynkTask da aggiornare.

In Classe di attività: updateTextView public static void() {

// qui il codice }

In AynckTask classe chiamata di questa funzione.

+0

perfetto. Grazie! – hoss

3

Ho scritto una piccola estensione su AsyncTask per questo tipo di scenario. Esso consente di mantenere l'AsyncTask in una classe separata, ma ti dà anche un comodo accesso al completamento del task:

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

} 

Quindi, prima di estendere ListenableAsyncTask invece di AsyncTask. Quindi, nel codice UI, crea un'istanza concreta e imposta listenWith (...).

2

La questione è già stata risolta, ancora im distacco come dovrebbe essere fatto immagino ..

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

ora nella classe asincrona

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

// inserire questo codice all'interno della vostra classe di attività e anche dichiarare l'aggiornamento TextView statico

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

Uso dell'interfaccia 1) Creare un'interfaccia

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

2) Implementa nella vostra attività

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) Crea costruttore in AsyncTask (Attività attività) {} Registrare l'interfaccia nel file AsyncTask e metodo di interfaccia chiamata come di seguito.

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

} 

Qui, la vostra OnPostExecute chiamerà dopo tutto lavoro fatto dalla AsyncTask e otterrà "risultato" come parametro, restituito da doInBackground() {return "";}.

Mentre "dataSendToActivity.sendData (risultato);" chiamerà il metodo sovrascritto dell'attività "public void sendData (String str) {}".

un caso limite da ricordare: essere sicuri di passare this, vale a dire si contesto di attività in corso per AsyncTask e non creare un'altra istanza della vostra attività, altrimenti il ​​vostro Activity saranno distrutti e uno nuovo è stato creato.

+0

Questo forse al primo sguardo, non può gestire più generale 'AsyncTask' in un'attività. – zionpi

+0

Questa è una buona soluzione. L'implementazione di un'interfaccia allenta l'accoppiamento ed è consigliata in questo video degli sviluppatori Android: https://www.youtube.com/watch?v=jtlRNNhane0&index=4&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE. –

Problemi correlati