AsyncTask - nigdy nie kończy działania

0

Witam.

Walczę z AsyncTask w Androidzie.

Stworzyłem klasę która ma pobierać treść www.
Chciałem do tego celu wykorzystać AsyncTask.

Klasa wygląda tak:

public class WebConnector {
    public AsyncTask<String, Void, String> GetContent = new AsyncTask<String, Void, String>() {
        @Override
        protected String doInBackground(String... params) {
            String fullString = params[0];
            Log.d("WebConnector", "AsyncClic doInBackground! ");
		// tu znajdzie się kod odpowiedzialny za pobieranie strony
            return  fullString;
        }

        @Override
        protected void onPreExecute() {
            Log.d("WebConnector", "AsyncClic PreExecute! ");
        }

        @Override
        protected void onPostExecute(String s) {
            Log.d("WebConnector", "AsyncClic PostExecute! ");
        }
    };
}

W głównej klasie stworzyłem obiekt WebConnector a w zdarzeniu przycisku dodałem:

 try {
                    String content = wsc.GetContent.execute("test").get();
                    Log.d("MainClass", content);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }

Problem w tym że przycisk działa tylko raz, wtedy w logu widzę:

10-26 23:16:39.772 14672-14672/com.example.user.myapplication D/WebConnector: AsyncClic PreExecute! 
10-26 23:16:39.773 14672-15002/com.example.user.myapplication D/WebConnector: AsyncClic doInBackground! 
10-26 23:16:39.773 14672-14672/com.example.user.myapplication D/MainClass: test
10-26 23:16:39.788 14672-14672/com.example.user.myapplication D/WebConnector: AsyncClic PostExecute! 

drugie kliknięcie powodwuje wyjątek:

10-26 23:16:49.619 14672-14672/com.example.user.myapplication E/AndroidRuntime: FATAL EXCEPTION: main
                                                                                Process: com.example.user.myapplication, PID: 14672
                                                                                java.lang.IllegalStateException: Cannot execute task: the task has already been executed (a task can be executed only once)
                                                                                    at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:605)

Jeżeli metoda przechodzi do bloku onPostExecute to chyba kończy swoje działanie?
Co w tej sytuacji powinienem zrobić?
Przy każdym kliknięciu tworzyć nową instancję klasy WebConnector?

Z góry dziękuje za pomoc.

1

utworzyć nowy task. masz napisane że ten juz się zakończył.
https://developer.android.com/reference/android/os/AsyncTask.html

0

Nie wiem jak, ale źle sobie przetłumaczyłem treść wyjątku :).

Przerobiłem to w ten sposób:

public class WebServiceConnector {
    public String GetContent(String... params) throws ExecutionException, InterruptedException {
        String ret = new AsyncTask<String, Void, String>() {
            @Override
            protected String doInBackground(String... params) {
                String fullString = params[0];
                Log.d("WebConnector", "AsyncClic doInBackground! ");
                return  fullString;
            }

            @Override
            protected void onPreExecute() {
                Log.d("WebConnector", "AsyncClic PreExecute! ");
            }

            @Override
            protected void onPostExecute(String s) {
                Log.d("WebConnector", "AsyncClic PostExecute! ");
            }
        }.execute(params).get();

        return ret;
    }  
}

Działa, ale pytanei czy tak jest "elegancko" ;)?

0

@hipekk: ja bym stworzył osobną klasę dziedziczącą po AsyncTask.

1

@hipekk: Co do Twojego kodu to nie powinieneś używać get(), gdyż blokuje to wątek i czeka na zakończenie asynctaska, więc dopóki task nie zakonczy działania to Twoje UI bedzie nieaktywne.
Żeby zrobić to poprawnie najlepiej jest użyć Callbacka i powiadomić o wyniku w funkcji onPostExecute.
Funkcja doInBackground wykonuje sie w wątku w tle, onPostExecute wywoluje się w wątku UI, wiec masz tam bezpieczny dostęp do kontrolek na ekranie.

Przykład:

public class ExampleTask extends AsyncTask<Void,Void,String> {

        interface Callback {
            void onError();
            void onSucccess(String result);
        }

        private Callback callback;

        public ExampleTask(Callback callback) {
            // dostajesz referencje do callbacku w konstruktorze
            this.callback = callback;
        }

        @Override
        protected String doInBackground(Void... voids) {

            // tutaj sobie coś robisz w wątku w tle

            return "wynik";
        }

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

            // wątek w UI - przekazuje info ze cos sie udalo lub nie
            this.callback.onSucccess(result);
        }
    }

A to jak tworzysz task i przekazujesz mu callback

ExampleTask task = new ExampleTask(new ExampleTask.Callback() {
            @Override
            public void onError() {
                // wyswietlasz blad, komunikat czy cokolwiek
                Toast.makeText(activity, "Wystapil bład", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onSucccess(String result) {

                // w przypadku sukcesu np aktualizujesz textview:
                textView.setText(result);

            }
        });
task.execute();
0

@Hagefid dzięki wielkie za pomoc.

Akurat w tym przypadku potrzebuje aby UI "zaczekało" na wynik tej metody (wrzuciłem ją do AsyncTaska tylko dlatego że dane pobierane są z Internetu a z tego co wyczytałem połączenie z Internetem musi być w osobnym wątku), ale na przyszłość na pewno się przyda :).

0

@hipekk: Jeżeli UI musi zaczekać to możesz na starcie aplikacji wyświetlić animację ładowania (ProgressBar) a w metodzie onSuccess ukryć ją i pokazać widok z danymi. Nie powinno się blokować wątku UI, bo od strony użytkownika wyglądałoby to tak jakby aplikacja się zacięła (np może to wystąpić, gdy użytkownik ma problem zasięgiem sieci).

1 użytkowników online, w tym zalogowanych: 0, gości: 1