W moim działaniu używam klasy, która pochodzi od AsyncTask i parametru, który jest wystąpieniem tego AsyncTask. Kiedy dzwonię, mInstanceOfAT.execute("")
wszystko jest w porządku. Ale aplikacja ulega awarii, gdy naciskam przycisk aktualizacji, który ponownie wywołuje AsyncTask (na wypadek, gdyby zadanie sieciowe nie działało). Bo wtedy pojawia się Wyjątek, który mówi
Nie można wykonać zadania: zadanie zostało już wykonane (zadanie można wykonać tylko raz)
Próbowałem wywołać anulowanie (true) dla wystąpienia Asyctask, ale to też nie działa. Jak dotąd jedynym rozwiązaniem jest utworzenie nowych instancji Asyntask. Czy to właściwy sposób?
Dzięki.
źródło
Powody wystrzeliwania i zapomnienia instancji ASyncTask są dość dobrze opisane w odpowiedzi Steve'a Prentice'a - jednak chociaż jesteś ograniczony co do tego, ile razy wykonujesz ASyncTask, możesz robić, co chcesz, podczas gdy wątek jest uruchomiony. .
Umieść swój kod wykonywalny w pętli wewnątrz metody doInBackground () i użyj blokady współbieżnej, aby wyzwolić każde wykonanie. Wyniki można pobrać za pomocą funkcji publicProgress () / onProgressUpdate () .
Przykład:
class GetDataFromServerTask extends AsyncTask<Input, Result, Void> { private final ReentrantLock lock = new ReentrantLock(); private final Condition tryAgain = lock.newCondition(); private volatile boolean finished = false; @Override protected Void doInBackground(Input... params) { lock.lockInterruptibly(); do { // This is the bulk of our task, request the data, and put in "result" Result result = .... // Return it to the activity thread using publishProgress() publishProgress(result); // At the end, we acquire a lock that will delay // the next execution until runAgain() is called.. tryAgain.await(); } while(!finished); lock.unlock(); } @Override protected void onProgressUpdate(Result... result) { // Treat this like onPostExecute(), do something with result // This is an example... if (result != whatWeWant && userWantsToTryAgain()) { runAgain(); } } public void runAgain() { // Call this to request data from the server again tryAgain.signal(); } public void terminateTask() { // The task will only finish when we call this method finished = true; lock.unlock(); } @Override protected void onCancelled() { // Make sure we clean up if the task is killed terminateTask(); } }
Oczywiście jest to nieco bardziej skomplikowane niż tradycyjne użycie ASyncTask i rezygnuje się z użycia funkcji PublishProgress () do raportowania rzeczywistych postępów. Ale jeśli martwisz się pamięcią, to podejście zapewni, że tylko jedno ASyncTask pozostanie w stercie w czasie wykonywania.
źródło
IllegalMonitorStateException
wrunAgain
(nazywany przezonProgressUpdate
) zobaczyć tę odpowiedź: stackoverflow.com/a/42646476/2711811 . Sugeruje (i zadziałało dla mnie), żesignal()
trzeba otaczaćlock
/unlock
. Może to mieć związek z czasempublishProgress
dzwonieniaonProgressUpdate
.Miałem ten sam problem. W moim przypadku mam zadanie, które chcę wykonać w
onCreate()
i wonResume(
środku). Więc zrobiłem mój Asynctask statyczny i pobrałem z niego instancję. Teraz nadal mamy ten sam problem.Więc to, co zrobiłem w onPostExecute (), to:
instance = null;
Pamiętając, że sprawdzam w statycznej metodzie getInstance, że moja instancja nie jest pusta, w przeciwnym razie ją tworzę:
if (instance == null){ instance = new Task(); } return instance;
Metoda w postExecute opróżni instancję i utworzy ją ponownie. Oczywiście można to zrobić poza zajęciami.
źródło
Moje zadania rotacji stały się statyczne, co pomogło mi następnie dołączyć, odłączyć i ponownie dołączyć je do wątków interfejsu użytkownika przy zmianach rotacji. Ale wracając do twojego pytania, tworzę flagę, aby sprawdzić, czy wątek jest uruchomiony. Kiedy chcesz zrestartować wątek, sprawdzam, czy zadanie rotacji jest uruchomione, jeśli tak, to ostrzeżenie. Jeśli tak nie jest, ustawiam go na zero, a następnie tworzę nowy, który obejdzie błąd, który widzisz. Ponadto, po pomyślnym zakończeniu, anuluję ukończone zadanie świadome rotacji, aby było gotowe do ponownego wykonania.
źródło
Tak, to prawda, doktor mówi, że można wykonać tylko jedno Asyntask.
Za każdym razem, gdy chcesz go użyć, musisz wykonać:
// Any time if you need to call her final FirmwareDownload fDownload = new FirmwareDownload(); fDownload.execute("your parameter"); static class FirmwareDownload extends AsyncTask<String, String, String> { }
źródło