Czytałem o tym AsyncTask
i wypróbowałem poniższy prosty program. Ale to nie działa. Jak mogę to zrobić?
public class AsyncTaskActivity extends Activity {
Button btn;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = (Button) findViewById(R.id.button1);
btn.setOnClickListener((OnClickListener) this);
}
public void onClick(View view){
new LongOperation().execute("");
}
private class LongOperation extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
for(int i=0;i<5;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");
return null;
}
@Override
protected void onPostExecute(String result) {
}
@Override
protected void onPreExecute() {
}
@Override
protected void onProgressUpdate(Void... values) {
}
}
}
Próbuję tylko zmienić etykietę po 5 sekundach w tle.
To jest mój main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="false"
android:max="10"
android:padding="10dip">
</ProgressBar>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Progress" >
</Button>
<TextView android:id="@+id/output"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Replace"/>
</LinearLayout>
Odpowiedzi:
Ok, próbujesz uzyskać dostęp do GUI przez inny wątek. Zasadniczo nie jest to dobra praktyka.
AsyncTask wykonuje wszystko
doInBackground()
wewnątrz innego wątku, który nie ma dostępu do GUI, w którym znajdują się twoje widoki.preExecute()
ipostExecute()
oferują dostęp do GUI przed i po tym, jak w tym nowym wątku nastąpi duże podnoszenie, a wynik długiej operacji można nawet przekazaćpostExecute()
aby następnie wyświetlić wyniki przetwarzania.Zobacz następujące wiersze, w których później aktualizujesz TextView:
Włóż je
onPostExecute()
.Zobaczysz wtedy tekst TextView zaktualizowany po
doInBackground
.Zauważyłem, że Twój odbiornik onClick nie sprawdza, który widok został wybrany. Uważam, że najłatwiej to zrobić za pomocą instrukcji switch. Mam poniżej pełną klasę ze wszystkimi sugestiami, aby uniknąć zamieszania.
źródło
onPostExecute(String result)
metody. Ułatwi to przyszłym czytelnikom, że argument jest wypełniany wartością zwracanądoInBackground(String... params)
.Moja pełna odpowiedź jest tutaj , ale tutaj znajduje się objaśniający obraz uzupełniający inne odpowiedzi na tej stronie. Dla mnie zrozumienie, dokąd zmierzają wszystkie zmienne, było najbardziej mylącą częścią na początku.
źródło
params
jest tablicą. (W powyższym przykładzie była toString
tablica). Pozwala to na przekazanie wielu parametrów tego samego typu. Następnie można uzyskać dostęp do tych parametrów, zparams[0]
,params[1]
,params[2]
, itd. Na przykład, nie było tylko jednoString
wparams
tablicy. Jeśli chcesz przekazać wiele parametrów różnych typów (na przykład aString
i anint
), zobacz to pytanie .Jestem pewien, że działa poprawnie, ale próbujesz zmienić elementy interfejsu w wątku w tle, ale to się nie uda.
Sprawdź swoje połączenie i AsyncTask w następujący sposób:
Klasa wzywająca
Uwaga: Osobiście sugeruję używanie
onPostExecute()
gdziekolwiek wykonujesz swój wątek AsyncTask, a nie w klasie, która rozszerza sam AsyncTask. Myślę, że dzięki temu kod jest łatwiejszy do odczytania, zwłaszcza jeśli potrzebujesz AsyncTask w wielu miejscach, z nieco innymi wynikami.Klasa LongThread (rozszerza AsyncTask):
źródło
onPostExecute
aktywności jest genialne.Stworzyłem prosty przykład korzystania z AsyncTask Androida. Zaczyna się od
onPreExecute(), doInBackground(), publishProgress()
i wreszcieonProgressUpdate()
.W tym doInBackground () działa jako wątek tła, podczas gdy inne działają w wątku interfejsu użytkownika. Nie możesz uzyskać dostępu do elementu interfejsu użytkownika w doInBackground (). Sekwencja jest taka sama, jak wspomniałem.
Jednakże, jeśli trzeba zaktualizować dowolny widget z
doInBackground
możnapublishProgress
zdoInBackground
którym będzie zadzwonićonProgressUpdate
, aby zaktualizować widget UI.Nazwij to tak w swojej działalności:
Dokumentacja programisty tutaj
źródło
Przenieś te dwie linie:
z metody AsyncTask
doInBackground
i umieść je wonPostExecute
metodzie. TwójAsyncTask
powinien wyglądać mniej więcej tak:źródło
AsyncTask
, na które moja odpowiedź odpowiada; i wysyłanie wartości z usługi do wątku interfejsu użytkownika, do którego odnosi się druga dyskusja. Te kwestie są niezależne.Tło / teoria
AsyncTask pozwala uruchomić zadanie w wątku w tle, publikując wyniki w wątku interfejsu użytkownika.
Realizacja
AsyncTask to klasa ogólna. (Wymaga sparametryzowanych typów w swoim konstruktorze).
Wykorzystuje te trzy ogólne typy:
Params
- rodzaj parametrów wysyłanych do zadania po wykonaniu.Progress
- rodzaj jednostek postępu opublikowanych podczas obliczeń w tle.Result
- rodzaj wyniku obliczeń w tle.Te trzy parametry odpowiadają trzem podstawowym funkcjom, w których można zastąpić
AsyncTask
:doInBackground(Params...)
onProgressUpdate(Progress...)
onPostExecute(Result)
Aby wykonać AsyncTask
execute()
z parametrami, które zostaną wysłane do zadania w tle.Co się dzieje
Na głównym wątku / UI ,
onPreExecute()
jest tzw.W wątku tła ,
doInBackground(Params...)
jest tzw.Params
zostały przekazane przezexecute
.)Musi zastąpić co najmniej,
doInBackground()
aby użyć AsyncTask.Wywołanie w
publishProgress(Progress...)
celu zaktualizowania interfejsu użytkownika z wyświetlaniem postępu (np. Animacja interfejsu użytkownika lub wydrukowany tekst dziennika), gdy obliczenia w tle są nadal wykonywane.onProgressUpdate()
wezwanie.W wątku tła wynik jest zwracany
doInBackground()
.Na głównym wątku / UI ,
onPostExecute()
jest wywoływana z zwróconego wyniku.Przykłady
W obu przykładach „zadanie blokujące” to pobieranie z Internetu.
Przykład A
doInBackground()
Metoda pobiera obraz i zapisuje go w obiekcie typu bitmapy.onPostExecute()
Metoda bierze bitmapę i umieszcza go w ImageView.Przykład B
Przykład wykonania B.
źródło
Po wykonaniu zadania asynchronicznego zadanie przechodzi przez cztery etapy:
Poniżej znajduje się przykład demonstracji:
Po utworzeniu zadanie jest wykonywane bardzo prosto:
źródło
Najkrótszy przykład robienia czegoś asynchronicznie:
Aby uruchomić:
źródło
Jak zapamiętać parametry używane w AsyncTask?
Jeśli dopiero zaczynasz korzystać z AsyncTask, często zdarza się, że możesz się pomylić podczas pisania AsyncTask. Głównymi winowajcami są parametry używane w AsyncTask, tj
AsyncTask<A, B, C>
. W oparciu o podpisy A, B, C (argumenty) metod różnią się, co jeszcze bardziej komplikuje sytuację.Nie komplikuj!
Kluczem jest nie zapamiętywać . Jeśli potrafisz sobie wyobrazić, co naprawdę musisz zrobić, to napisanie AsyncTask z poprawnym podpisem przy pierwszej próbie byłoby bułką z masłem. Wystarczy dowiedzieć się, co się
Input
,Progress
iOutput
to, i będzie dobrze iść.Czym jest AsyncTask?
AsyncTask to zadanie w tle uruchamiane w wątku w tle. To zajmuje
Input
, wykonujeProgress
i dajeOutput
.Na przykład:
Jaki jest związek z metodami?
Jak napisać to w kodzie?
Jak uruchomisz to zadanie?
źródło
W wątku roboczym nie można bezpośrednio manipulować elementami interfejsu użytkownika w systemie Android.
Jeśli używasz AsyncTask, zapoznaj się z metodami oddzwaniania.
Na przykład:
FYI: Aby uzyskać dostęp do wątku interfejsu użytkownika z wątku roboczego, możesz albo użyć metody runOnUiThread (), albo metody post w widoku.
Na przykład:
Pomoże Ci to lepiej poznać sytuację. Dlatego w twoim przypadku musisz ustawić widok tekstu w metodzie onPostExecute ().
źródło
Poleciłbym ułatwić Ci życie, korzystając z tej biblioteki do prac w tle:
https://github.com/Arasthel/AsyncJobLibrary
To takie proste ...
źródło
Przykładowe zadanie asynchroniczne z żądaniem POST:
źródło
Po prostu:
źródło
Musisz zadeklarować przycisk onclicklistener. Po kliknięciu wywołuje klasę AsyncTask DownloadJson.
Proces zostanie pokazany poniżej:
źródło
źródło
Aktualizacja: marzec 2020 r
Zgodnie z oficjalną dokumentacją dewelopera Androida AsyncTask jest teraz przestarzały.
Zamiast tego zaleca się stosowanie kororyn Kotlin . Po prostu pozwala pisać zadania asynchroniczne w stylu sekwencyjnym.
źródło
Przykładowy przykład AsyncTask z postępem
źródło
Zadanie ASync;
źródło
MyTask
w klasieMainActivity
? Czy to jest zwyczajowe?Podczas pracy z AsyncTask konieczne jest utworzenie następcy klasy i zarejestrowanie w nim implementacji niezbędnych dla nas metod. W tej lekcji przyjrzymy się trzem metodom:
doInBackground - zostanie wykonany w nowym wątku, a tutaj rozwiązujemy wszystkie nasze trudne zadania. Ponieważ wątek inny niż podstawowy nie ma dostępu do interfejsu użytkownika.
onPreExecute - wykonywany przed doInBackground i ma dostęp do interfejsu użytkownika
onPostExecute - wykonywany po doInBackground (nie działa, jeśli AsyncTask został anulowany - o tym w następnych lekcjach) i ma dostęp do interfejsu użytkownika.
To jest klasa MyAsyncTask:
Oto jak wywołać swoją Aktywność lub Fragment:
źródło
jeśli otworzysz klasę AsyncTask, zobaczysz poniższy kod.
Funkcje AsyncTask
przykład
źródło
Zmień kod, jak podano poniżej:
źródło