MójDroid.pl

#16 Twórz aplikacje na Androida z Mojdroid.pl – AsyncTask

2012-10-04
|
Damian P.

AsyncTask to kolejny sposób ma przetwarzanie zadań w tle i wyświetlanie wyników w wybranej przez nas części aplikacji. W przeciwieństwie jednak do poprzednich rozwiązań, tutaj nie musimy zaprzątać sobie głowy tworzeniem osobnych wątków i Handlerów aby uzyskać wymarzony efekt, chociaż sama klasa została na nich oparta w pewnym stopniu.
Informacja: Nie radzisz sobie z kodem? Coś Ci nie wychodzi lub nie działa? Zgubiłeś się? W tym miejscu zobaczysz pełen kod aplikacji, a tutaj go pobierzesz na dysk.
Jak wiecie, tworzenie nowych Threadów mocno wpływa na długość działania urządzenia na baterii. Dzieje się tak dlatego, ponieważ nowy wątek korzysta w pełni z dostępnych zasobów procesora. Nie jest to więc zbyt dobre rozwiązanie wtedy, gdy chcemy wykonać jakieś proste działania. Od tego jest właśnie AsyncTask - nie tworzy on osobnych procesów (więc poprawia wydajność akumulatora), ale jednocześnie nie pozwala na prowadzenie zbyt skomplikowanych obliczeń (bo działa w głównym procesie programu, przez co może go zawiesić na sekundę jeżeli go źle użyjemy). Tak więc nowe wątki powinniśmy tworzyć tylko wtedy, gdy większa moc będzie nam [szybko] potrzebna, w innych wypadkach powinniśmy ograniczyć się do samego AsyncTaska i ewentualnie Handlerów. Istnieją również rozszerzenia takie jak FutureTask, Executor i ThreadPoolExecutor, które mogą być przydatne do dłuższych obliczeń, ale to nie temat na dziś.

1. AsyncTask

Oczywiście podobnie jak poprzednie rozwiązania do działania w tle, tak i AsyncTask jest asynchroniczny. Oznacza to, że wyniki wewnątrz niego będą publikowane od razu wtedy, gdy będą dostępne, a wszystkie operacje będą wykonywane (więc i wyświetlane) nieregularnie. Sama klasa Async'a składa się z kilku ważnych części. Przy deklaracji nowego zadania musimy określić jakiego typu dane będą dostępne na samym początku, jakie przy sprawdzaniu postępu, a jakie po wykonaniu pojedynczego (!) zadania. Do każdej z tej części istnieje dodatkowo metoda, która pozwala zarządzać wybranymi zdarzeniami (np. przed wykonaniem nowego zadania czy w trakcie niego). Jedna z nich oczywiście jest wymagana i jest to doInBackground, która odpowiada za wykonywanie zadania, jakie stawiamy przed AsyncTaskiem. Co ważne (jak pisałem przed chwilą), na wejściu AsyncTask przyjmuje nie pojedyncze elementy a ich tablicę (zbiór), więc gdy chcemy obrobić jeden element, musimy to uwzględnić w kodzie (wybierając element 0 z całej tablicy). Całość może brzmieć nieco bez ładu i składu, ale w rzeczywistości wszystko jest bardzo proste. Poniżej znajdziecie mój przykład wykorzystania AsyncTasku, który będzie przerabiać kilka zdań na nowe (i pokazywać je w TextView), z dołączoną częścią na początku:
package com.example.moja.pierwsza.aplikacja;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.TextView;

public class View_AsyncTask extends Activity {

    TextView tv1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);

	setContentView(R.layout.view_thread);
	tv1 = (TextView) findViewById(R.id.tV_thread);

	String[] dane = { "Przykład 1", "Przykład 2", "Przykład 3" };
	
	new NaszAsyncTask().execute(dane);

    }

    private class NaszAsyncTask extends AsyncTask<String, String, String> {

	@Override
	protected void onProgressUpdate(String... values) {
	    super.onProgressUpdate(values);
	    // aktualizacja stanu podczas działania, tutaj zmiana tresci textview na inny
	    // w values będziemy przesyłać tylko jedna wartosc
	    
	    tv1.setText(values[0]);
	}

	@Override
	protected void onPostExecute(String result) {
	    super.onPostExecute(result);
	    // działania po wykonaniu zdania w doInBackground
	    // ta metoda działa w UI, więc możesz zmieniać różne elementy!

	    tv1.setText(result);
	}

	@Override
	protected void onPreExecute() {
	    super.onPreExecute();
	    // działania przed wykonaniem zadań
	    // ta metoda działa w UI, więc możesz zmieniać różne elementy!
	    
	    tv1.setText("Przetwarzanie");
	}

	@Override
	protected String doInBackground(String... params) {
	    // zadanie do wykonania
	    // tutaj nie możesz nic zmieniać w UI, tylko wykonywać obliczenia i zadania
	    
	    // Dla wydajności zapisujemy wielkosc tablicy przed pętlą
	    final int wielkosctablicy = params.length; 
	    	    
	    for (int i=0;i<wielkosctablicy;i++) {
		String nasztekst = params[i];
		publishProgress("Przetworzono " + nasztekst);	
	    }
	    
	    return "Wykonano wszystkie działania, łącznie " + wielkosctablicy;
	}

    }

}
Każdą część prosto opisałem, więc problemy ze zrozumieniem nie powinny występować. Nazwa każdego zdarzenia mówi o tym, do czego służy. AsyncTask zaczyna działać wtedy, gdy wywołamy na naszej stworzonej klasie funkcję .execute z wybranymi przez nas danymi (tablicę, jak wiecie, gdzie każdy element jest taki sam jak wybrany w klasie). Gdzie możemy znaleźć AsyncTaski? Praktycznie w każdej aplikacji, która ładuje jakieś dane z zewnątrz - czy to obrazy, dane tekstowe czy filmy. Całość jest prosta do stworzenia, nie potrzebuje zbyt wiele zasobów ,a efekt jest po prostu dobry.