2012-09-03 8 views
36

Nienawidzę wewnętrznej klasy.Android: Jak zaktualizować interfejs użytkownika z AsyncTask, jeśli AsyncTask jest w osobnej klasie?

Mam główną aktywność, która uruchamia "AsyncTask" o krótkim czasie życia.

AsyncTask jest w oddzielnym pliku, nie jest wewnętrzną klasy działalności głównej

muszę asynchroniczny zadanie aktualizuje TextView od głównej działalności.

wiem mogę zaktualizować TextView z onProgressUpdate, jeśli AsyncTask jest klasa wewnętrzna

Ale jak z zewnętrznego, Niezależne, zadania asynchroniczny?

UPDATE: wygląda to jak praca:

W tym aktywność zgłoszę Zadaniem

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

W konstruktorze mam

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

gdzie debugowania była prywatna pole AsyncTask.

Więc onProgressUpdate mogę

debug.append(text); 

Dzięki za wszystkie sugestie

+0

Masz na myśli, że w innej klasie chcesz uzyskać dostęp do interfejsu użytkownika? –

+0

Tak. Muszę zaktualizować TextView z AsyncTask. – realtebo

+0

Możesz przekazać kontekst w swoim konstruktorze i przesyłając go do swojej klasy ActivityClass, możesz zmienić textView za pomocą metody runOnUIThread. –

Odpowiedz

31

EDIT edytowany odpowiedź używać WeakReference


AsyncTask zawsze jest oddzielna klasa od Activity, ale podejrzewam, że to znaczy, że jest w innym pliku niż pliku klasy aktywności, więc nie można korzystać z bycie wewnętrzną klasą aktywności. Wystarczy przekazać kontekst działalność jako argumentu do Async zadania (czyli jej konstruktora)

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

    WeakReference<Activity> mWeakActivity; 

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

... 

i używać, gdy trzeba go (Pamiętaj, aby nie używać w czasie doInBackground()), czyli tak, kiedy normalnie zadzwonić

int id = findViewById(...) 

w AsyncTask zadzwonić tj

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

pamiętać, że nasz Activity można już podczas doInBackground() jest w toku (tak referen nce zwrócony może stać się null), ale przez użycie WeakReference nie zapobiegamy gromadzeniu go przez GC (i nieszczelności pamięci), a ponieważ Aktywność już nie istnieje, zwykle nie ma sensu nawet próbować aktualizować jej stan (nadal, w zależności od logiki, którą możesz chcieć zrobić coś w rodzaju zmiany wewnętrznego stanu lub aktualizacji DB, ale dotykanie interfejsu użytkownika musi zostać pominięte).

+2

Jeśli przejdziesz tę trasę, lepiej trzymać odwołanie do działania jako WeakReference zamiast po prostu Aktywność. IMO. – newbyca

+0

Co to jest "WeakReference"?! – realtebo

+0

WebnetMobile.com, ach, ok, nie byłem pewien, dobrze wiedzieć. @realtebo, http://developer.android.com/reference/java/lang/ref/WeakReference.html – newbyca

3

Wystarczy przekazać kontekst (działanie lub cokolwiek) do AsyncTask w konstruktorze i następnie w onSuccess lub onProgressUpdate rozmowy co trzeba w kontekście.

2

Utwórz funkcję statyczną w kontekście klasy zajęć, aby zaktualizować widok tekstowy, a następnie wywołać tę funkcję w klasie AsynkTask w celu aktualizacji.

W klasie aktywny: public static void updateTextView() {

// kod tutaj }

W AynckTask klasy wywołać tę funkcję.

+0

doskonały. Dzięki! – hoss

3

Napisałem małe rozszerzenie AsyncTask dla tego rodzaju scenariusza. To pozwala utrzymać AsyncTask w oddzielnej klasie, ale także daje wygodny dostęp do zakończenia zadania to:

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

} 

Więc najpierw rozszerzyć ListenableAsyncTask zamiast AsyncTask. Następnie w swoim kodzie UI wprowadź konkretną instancję i ustaw listenear (...).

2

Pytanie zostało już odpowiedział jeszcze im wpis, jak powinno się to odbywać myślę ..

klasa główną działalność

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

teraz w klasie asynchronicznym

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

// miejsce to kod wewnątrz klasy aktywności, a także zadeklarować aktualizowania TextView statycznego

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

Korzystanie z interfejsu 1) Utwórz jeden interfejs

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

2) Realizuje go w swojej działalności

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) Utwórz konstruktor w AsyncTask (Aktywność aktywności) {} Zarejestruj swój interfejs w pliku AsyncTask i metodę interfejsu wywołań jak poniżej.

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

} 

Tutaj swoją OnPostExecute zadzwoni po wszystkich zadań wykonanych przez AsyncTask i dostanie "wynik" jako parametr, zwrócony przez doInBackground() {return "";}.

Podczas gdy "dataSendToActivity.sendData (wynik);" będzie wywoływał nadpisaną przez funkcję metodę "public void sendData (String str) {}".

przypadek krawędź do zapamiętania: Pamiętaj, aby przejść this, to znaczy ty kontekst bieżącej działalności do AsyncTask i nie utworzyć inną instancję swojej działalności, w przeciwnym razie Activity zostaną zniszczone i tworzony jest nowy.

+0

To może na pierwszy rzut oka, nie może obsłużyć wielu ogólnych "AsyncTask" w jednym działaniu. – zionpi

+0

To jest dobre rozwiązanie. Wdrożenie interfejsu powoduje poluzowanie złącza i jest zalecane w tym wideo dla programistów Androida - https://www.youtube.com/watch?v=jtlRNNhane0&index=4&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE. –

Powiązane problemy