2012-06-10 9 views
43

Mam następujące klasy:Jak uzyskać ciąg od AsyncTask?

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

@Override 
protected String doInBackground(String... params) { 
    String line; 
    try { 
     DefaultHttpClient httpClient = new DefaultHttpClient(); 
     HttpPost httpPost = new HttpPost(params[0]); 

     HttpResponse httpResponse = httpClient.execute(httpPost); 
     HttpEntity httpEntity = httpResponse.getEntity(); 
     line = EntityUtils.toString(httpEntity); 

    } catch (UnsupportedEncodingException e) { 
     line = "<results status=\"error\"><msg>Can't connect to server</msg></results>"; 
    } catch (MalformedURLException e) { 
     line = "<results status=\"error\"><msg>Can't connect to server</msg></results>"; 
    } catch (IOException e) { 
     line = "<results status=\"error\"><msg>Can't connect to server</msg></results>"; 
    } 
    return line; 
} 

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

} 

I staram się nazwać tak:

String output = null; 
output = new getURLData().execute("http://www.domain.com/call.php?locationSearched=" + locationSearched); 

Ale zmienna wyjściowa nie jest uzyskiwanie danych, zamiast ja dostaję błąd:

Type mismatch: cannot convert from AsyncTask<String,Integer,String> to String 
+0

skąd masz zrobić "super.onPostExecute (wynik);'? Nie wstawiłem tej linii i nadal działa! –

Odpowiedz

101

Sposób execute wraca sama AynscTask, trzeba zadzwonić get:

output = 
    new getURLData() 
     .execute("http://www.example.com/call.php?locationSearched=" + locationSearched) 
     .get(); 

ta rozpocznie nowy wątek (poprzez execute) podczas blokowania bieżącego wątku (przez get) do pracy z nowym wątku została zakończona, a wynik został zwrócony.

Jeśli to zrobisz, po prostu odwrócił swoją asynchroniczny zadanie do synchronizacji jednym.

Jednak problem z używaniem get polega na tym, że ponieważ blokuje, musi być wywołany w wątku roboczym. Jednak na głównym wątku należy wywołać AsyncTask.execute(). Więc chociaż ten kod może zadziałać, możesz uzyskać niepożądane wyniki. Podejrzewam również, że get() jest niedostatecznie testowane przez Google i możliwe jest, że wprowadzili błąd w dowolnym miejscu.

referencyjny: AsyncTask.get

+3

Mój Boże, to staje się bardziej skomplikowane, im dalej wchodzę ... Wszystko, co chcę zrobić, to kiedy użytkownik klika przycisk, ładuje ekran w prosty sposób, a następnie wyświetla zawartość z http, kiedy jest skończona. Jak to się robi? – Paul

+3

@Paul: Cokolwiek musisz zrobić po wykonaniu, zrób to na 'onPostExecute'. Czy _that_ simple ... –

+2

Żałuję, że nie było, ale jeśli przenieść przenieść do metody onPostExecute nie mam zmiennych params i więcej problemów powstaje zwracając ciąg. Doceniam twoją pomoc, ale zajęło mi to wiele godzin, naprawdę myślę, że to jest przegrana sprawa. – Paul

15

Wolę tworzyć zwrotnego niż nici blok UI. W swojej klasie utwórz metodę, która będzie wywoływana po otrzymaniu danych. Na przykład:

private void setData(String data){ 
    mTextView.setText(data); 
} 

Następnie w AsyncTask wdrożyć onPostExecute:

@Override 
protected void onPostExecute(String result) { 
    setData(result); 
} 

A potem gdzieś w kodzie po prostu wykonać zadanie:

new getURLData().execute(... 

Kiedy zadanie kończy setData jest wywoływany i mTextView jest wypełniona.

AsyncTask.get() będzie blokować twój interfejs użytkownika, więc nie ma powodu, aby używać AsyncTask.

+9

świetnie, ale jak mogę nazwać 'setData' z AsyncTask, jeśli ta metoda jest w innym działaniu (tym, który robi' .execute')? –

+2

Ty nie. Po prostu rób to, czego potrzebujesz w [onPostExecute()] (http://developer.android.com/reference/android/os/AsyncTask.html#onPostExecute%28Result%29) – Cyrille

4

Jeśli użytkownik kliknie przycisk, musi poczekać na treść, co robi w międzyczasie?

Może to zrobić:

  1. Użytkownik kliknie przycisk.
  2. You sprawdź łączność. Jeśli użytkownik nie jest podłączony do Internetu, powiadom go.
  3. Uruchamiasz IntentService wysyłając intencję, aby wysłać żądanie HTTP.
  4. Po zakończeniu żądania publikujesz powiadomienie.
  5. Użytkownik klika powiadomienie, które wraca do działania, które może wykonać następny krok.

Pozwala to użytkownikowi odejść i zrobić cokolwiek podczas przetwarzania żądania.

IntentService działa w tle we własnym wątku. Po otrzymaniu intencji działa on onHandleIntent(). Po zakończeniu tej metody usługa jest buforowana: nie jest aktywna, ale może ponownie uruchomić się szybko po pojawieniu się następnego zamiaru.

0

W poniższym kodzie otrzymuję ciąg (directorName) z AsyncTask ponownie.

public class GetDirector { 
    String id; 
    private String baseURL = "http://www.omdbapi.com/?i="; 
    private String finalURL = ""; 
    String theDirector; 

    public GetDirector(String imdbID) throws ExecutionException, InterruptedException { 
     id= imdbID; 
     finalURL = baseURL + id + "&plot=full&r=json"; 
     System.out.println("GetDirector. finalURL= " + finalURL); 
     theDirector = new GetDirectorInfo().execute().get(); 
    } 

    public String getDirector(){ 
     return theDirector; 
    } 

    private class GetDirectorInfo extends AsyncTask<Void, Void,String> { 
     @Override 
     protected String doInBackground(Void... params) { 
      String directorName = null; 

      ServiceHandler sh = new ServiceHandler(); 

      // Making a request to url and getting response 
      String jsonStr = sh.makeServiceCall(finalURL, ServiceHandler.GET); 
      System.out.println("Act_DetailsPage. jsonStr= " + jsonStr); 

      if (jsonStr != null) { 
       try { 
        JSONObject everything = new JSONObject(jsonStr); 

        directorName = everything.getString(JSON_Tags.TAG_DIRECTOR); 
        System.out.println("directorName= "+ directorName); 
       } catch (JSONException e) { 
        e.printStackTrace(); 
       } 
      } else { 
       System.out.println("Inside GetDirector. Couldn't get any data from the url"); 
      } 
      return directorName; 
     } 
    } 
} 
+4

Używając * get * przechodzisz synchronicznie, a więc pokonując cały cel AsyncTask, który ma wykonywać asynchronicznie. – mradzinski

0

Dodaj parametr kontekstu do konstruktora zadania, który odnosiłby się do obiektu, w którym będą przechowywane wynikowe dane.

2
  1. Get kontekstu w konstruktorze tak:

    public GetDataTask(Context context) {}

  2. utworzyć interfejs z metodą:

    void onDataRetrieved(String data);

  3. implementować interfejs w klasie, z której tworzysz obiekt zadania (np. MainActivity)

  4. Obsada kontekst do interfejsu i wywołać metodę onDataRetrieved

+0

Może to spowodować wyciek pamięci. Jeśli długotrwała operacja ma dostęp do kontekstu działania, asynktask uniemożliwiłby śledzenie działania w przypadku zmiany konfiguracji lub wycofania użytkownika z działania z jakiegoś powodu. –

+0

Konieczne jest użycie 'WeakReference actWeak = new WeakReference <> (activity)' po wysłaniu 'Activity' do' AsyncTask' w celu uniknięcia wycieków pamięci i odzyskania go za pomocą 'Activity act = actWeak.get()' in metoda 'doInBackground'. – isabsent

0

ten jeden LINER pracował dla mnie:

String result = MyasyncTask.execute(type, usrPhoneA, usrPWDA).get(); 
+0

Jak to działa, gdy zwraca zmienną AsycTask? –

+0

Zwraca wynik operacji w zmiennej "result" po przetworzeniu przez PHP funkcji logowania. Czytam, że nie jest to zadanie asynchroniczne, ale w moim przypadku jest w porządku. – francisqueins

+0

Mam zmienną asynctask i nie było zbyt wiele –

0

Jedynym sposobem, aby przesłać dane z AsyncTask do UI bez ból to autobus Otto lub Event. Zarejestruj metodę, która obsłuży wynik pod adnotacją @Subscribe w interfejsie użytkownika i post a message z wynikiem w postaci onPostExecute metody Twojego .

Powiązane problemy