Android
AsyncTask
Szukaj…
Parametry
Parametr | Detale |
---|---|
Params | typ parametrów wysyłanych do zadania po wykonaniu. |
Postęp | rodzaj jednostek postępu opublikowanych podczas obliczeń w tle |
Wynik | rodzaj wyniku obliczeń w tle. |
Podstawowe użycie
W działaniach i usługach Androida większość połączeń zwrotnych jest uruchamiana w głównym wątku . Ułatwia to aktualizację interfejsu użytkownika, ale wykonywanie zadań obciążających procesor lub operacje we / wy w głównym wątku może spowodować, że interfejs użytkownika zostanie wstrzymany i przestanie odpowiadać ( oficjalna dokumentacja dotycząca tego, co się wtedy stanie).
Możesz temu zaradzić, umieszczając cięższe zadania w tle.
Jednym ze sposobów na to jest użycie AsyncTask , który zapewnia platformę ułatwiającą łatwe korzystanie z wątku w tle, a także wykonywanie zadań wątku interfejsu użytkownika przed, w trakcie i po zakończeniu wątku w tle.
Metody, które można zastąpić podczas rozszerzania AsyncTask
:
-
onPreExecute()
: wywoływany w wątku interfejsu użytkownika przed wykonaniem zadania -
doInBackground()
: wywoływany w wątku tła natychmiast po zakończeniu wykonywaniaonPreExecute()
. -
onProgressUpdate()
: wywoływany w wątku interfejsu użytkownika po wywołaniupublishProgress(Progress...)
. -
onPostExecute()
: wywoływany w wątku interfejsu użytkownika po zakończeniu obliczeń w tle
Przykład
public class MyCustomAsyncTask extends AsyncTask<File, Void, String> {
@Override
protected void onPreExecute(){
// This runs on the UI thread before the background thread executes.
super.onPreExecute();
// Do pre-thread tasks such as initializing variables.
Log.v("myBackgroundTask", "Starting Background Task");
}
@Override
protected String doInBackground(File... params) {
// Disk-intensive work. This runs on a background thread.
// Search through a file for the first line that contains "Hello", and return
// that line.
try (Scanner scanner = new Scanner(params[0])) {
while (scanner.hasNextLine()) {
final String line = scanner.nextLine();
publishProgress(); // tell the UI thread we made progress
if (line.contains("Hello")) {
return line;
}
}
return null;
}
}
@Override
protected void onProgressUpdate(Void...p) {
// Runs on the UI thread after publishProgress is invoked
Log.v("Read another line!")
}
@Override
protected void onPostExecute(String s) {
// This runs on the UI thread after complete execution of the doInBackground() method
// This function receives result(String s) returned from the doInBackground() method.
// Update UI with the found string.
TextView view = (TextView) findViewById(R.id.found_string);
if (s != null) {
view.setText(s);
} else {
view.setText("Match not found.");
}
}
}
Stosowanie:
MyCustomAsyncTask asyncTask = new MyCustomAsyncTask<File, Void, String>();
// Run the task with a user supplied filename.
asyncTask.execute(userSuppliedFilename);
lub po prostu:
new MyCustomAsyncTask().execute(userSuppliedFilename);
Uwaga
Definiując AsyncTask
, możemy przekazać trzy typy między nawiasami < >
.
Zdefiniowane jako <Params, Progress, Result>
(patrz sekcja Parametry )
W poprzednim przykładzie użyliśmy typów <File, Void, String>
:
AsyncTask<File, Void, String>
// Params has type File
// Progress has unused type
// Result has type String
Void
jest używana, gdy chcesz oznaczyć typ jako nieużywany.
Zauważ, że nie możesz przekazać prymitywnych typów (tj. int
, float
i 6 innych) jako parametrów. W takich przypadkach powinieneś przekazać ich klasy otoki , np. Integer
zamiast int
lub Float
zamiast float
.
Cykl życia AsyncTask i aktywności
AsyncTasks nie śledzą cyklu życia instancji działania. Jeśli uruchomisz AsyncTask w działaniu i obrócisz urządzenie, działanie zostanie zniszczone i zostanie utworzona nowa instancja. Ale AsyncTask nie umrze. Będzie żył, dopóki się nie skończy.
Rozwiązanie: AsyncTaskLoader
Jedna podklasa ładowarki jest AsyncTaskLoader. Ta klasa wykonuje tę samą funkcję co AsyncTask, ale znacznie lepiej. Może łatwiej obsługiwać zmiany konfiguracji działania i zachowuje się w cyklach życia fragmentów i działań. Zaletą jest to, że AsyncTaskLoader może być używany w każdej sytuacji, w której używany jest AsyncTask. Za każdym razem, gdy dane muszą zostać załadowane do pamięci, aby obsłużyć działanie / fragment, AsyncTaskLoader może wykonać to zadanie lepiej.
Anulowanie zadania asynchronicznego
YourAsyncTask task = new YourAsyncTask();
task.execute();
task.cancel();
To nie kończy twojego zadania, jeśli było w toku, po prostu ustawia anulowaną flagę, którą można sprawdzić, sprawdzając wartość isCancelled()
przez isCancelled()
(zakładając, że twój kod jest aktualnie uruchomiony), wykonując następujące czynności:
class YourAsyncTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
while(!isCancelled()) {
... doing long task stuff
//Do something, you need, upload part of file, for example
if (isCancelled()) {
return null; // Task was detected as canceled
}
if (yourTaskCompleted) {
return null;
}
}
}
}
Uwaga
Jeśli AsyncTask zostanie anulowane podczas wykonywania doInBackground(Params... params)
wówczas metoda onPostExecute(Result result)
NIE zostanie wywołana po doInBackground(Params... params)
. Zamiast tego onCancelled(Result result)
aby wskazać, że zadanie zostało anulowane podczas wykonywania.
Postęp publikowania
Czasami musimy zaktualizować postęp obliczeń wykonanych przez AsyncTask
. Postęp ten może być reprezentowany przez ciąg, liczbę całkowitą itp. Aby to zrobić, musimy użyć dwóch funkcji. Najpierw musimy ustawić funkcję onProgressUpdate
której typ parametru jest taki sam, jak parametr drugiego typu w naszym AsyncTask
.
class YourAsyncTask extends AsyncTask<URL, Integer, Long> {
@Override
protected void onProgressUpdate(Integer... args) {
setProgressPercent(args[0])
}
}
Po drugie, musimy koniecznie użyć funkcji publishProgress
w funkcji doInBackground
, i to wszystko, poprzednia metoda wykona całą pracę.
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
return totalSize;
}
Pobierz obraz za pomocą AsyncTask na Androida
W tym samouczku wyjaśniono, jak pobrać obraz za pomocą AsyncTask na Androida. Poniższy przykład pobierania obrazu pokazuje pasek postępu podczas pobierania.
Zrozumienie Androida AsyncTask
Zadanie asynchroniczne umożliwia wdrożenie MultiThreading bez brudzenia rąk w wątkach. AsyncTask umożliwia prawidłowe i łatwe korzystanie z wątku interfejsu użytkownika. Umożliwia wykonywanie operacji w tle i przekazywanie wyników w wątku interfejsu użytkownika. Jeśli robisz coś izolowanego związanego z interfejsem użytkownika, na przykład pobierasz dane do przedstawienia na liście, skorzystaj z AsyncTask.- Z funkcji AsyncTasks najlepiej korzystać w przypadku krótkich operacji (maksymalnie kilka sekund).
- Zadanie asynchroniczne jest zdefiniowane przez 3 typy ogólne, o nazwie Params, Progress and Result, oraz 4 kroki, o
onPreExecute()
,doInBackground()
,onProgressUpdate()
ionPostExecute()
. - W
onPreExecute()
możesz zdefiniować kod, który należy wykonać przed rozpoczęciem przetwarzania w tle. - doInBackground ma kod, który należy wykonać w tle, tutaj w
doInBackground()
możemy wysyłać wyniki do wątku zdarzenia wielokrotnie za pomocą metody PublProgress (), aby powiadomić, że przetwarzanie w tle zostało zakończone, możemy po prostu zwrócić wyniki. -
onProgressUpdate()
odbiera aktualizacje postępu z metodydoInBackground()
, która jest publikowana zapublishProgress()
metodypublishProgress()
, i ta metoda może użyć tej aktualizacji postępu do aktualizacji wątku zdarzenia -
onPostExecute()
obsługuje wyniki zwrócone przezdoInBackground()
. - Stosowane typy ogólne to
- Parametry, typ parametrów wysyłanych do zadania po wykonaniu
- Postęp, rodzaj jednostek postępu opublikowanych podczas obliczeń w tle.
- Wynik, typ wyniku obliczenia w tle.
- Jeśli zadanie asynchroniczne nie korzysta z żadnych typów, można je oznaczyć jako Typ pustki.
- Uruchomione zadanie asynchroniczne można anulować, wywołując metodę
cancel(boolean)
.
Pobieranie obrazu za pomocą Android AsyncTask
twój układ .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" >
<Button
android:id="@+id/downloadButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click Here to Download" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="Your image will appear here" />
</LinearLayout>
klasa .java
package com.javatechig.droid;
import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class ImageDownladerActivity extends Activity {
private ImageView downloadedImg;
private ProgressDialog simpleWaitDialog;
private String downloadUrl = "http://www.9ori.com/store/media/images/8ab579a656.jpg";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.asynch);
Button imageDownloaderBtn = (Button) findViewById(R.id.downloadButton);
downloadedImg = (ImageView) findViewById(R.id.imageView);
imageDownloaderBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new ImageDownloader().execute(downloadUrl);
}
});
}
private class ImageDownloader extends AsyncTask {
@Override
protected Bitmap doInBackground(String... param) {
// TODO Auto-generated method stub
return downloadBitmap(param[0]);
}
@Override
protected void onPreExecute() {
Log.i("Async-Example", "onPreExecute Called");
simpleWaitDialog = ProgressDialog.show(ImageDownladerActivity.this,
"Wait", "Downloading Image");
}
@Override
protected void onPostExecute(Bitmap result) {
Log.i("Async-Example", "onPostExecute Called");
downloadedImg.setImageBitmap(result);
simpleWaitDialog.dismiss();
}
private Bitmap downloadBitmap(String url) {
// initilize the default HTTP client object
final DefaultHttpClient client = new DefaultHttpClient();
//forming a HttpGet request
final HttpGet getRequest = new HttpGet(url);
try {
HttpResponse response = client.execute(getRequest);
//check 200 OK for success
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w("ImageDownloader", "Error " + statusCode +
" while retrieving bitmap from " + url);
return null;
}
final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
try {
// getting contents from the stream
inputStream = entity.getContent();
// decoding stream data back into image Bitmap that android understands
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (Exception e) {
// You Could provide a more explicit error message for IOException
getRequest.abort();
Log.e("ImageDownloader", "Something went wrong while" +
" retrieving bitmap from " + url + e.toString());
}
return null;
}
}
}
Ponieważ obecnie nie ma pola komentarza dla przykładów (lub go nie znalazłem lub nie mam na to pozwolenia), oto komentarz na ten temat:
To dobry przykład tego, co można zrobić za pomocą AsyncTask.
Jednak przykład ma obecnie problemy z
- możliwe wycieki pamięci
- awaria aplikacji, jeśli obrót ekranu nastąpił na krótko przed zakończeniem zadania asynchronicznego.
Szczegółowe informacje:
- Przekaż aktywność jako Słaby Odniesienie, aby uniknąć wycieków pamięci
- http://stackoverflow.com/documentation/android/117/asynctask/5377/possible-problems-with-inner-async-tasks
- Unikaj przecieków Działania za pomocą AsyncTask
Przekaż aktywność jako Słaby Odniesienie, aby uniknąć wycieków pamięci
Często zdarza się, że AsyncTask wymaga odwołania do działania, które go wywołało.
Jeśli AsyncTask jest wewnętrzną klasą działania, możesz bezpośrednio do niego odwoływać i dowolne zmienne / metody składowe.
Jeśli jednak AsyncTask nie jest wewnętrzną klasą działania, konieczne będzie przekazanie odwołania do działania do AsyncTask. Po wykonaniu tej czynności jednym potencjalnym problemem, który może wystąpić, jest to, że AsyncTask zachowa odwołanie do działania, dopóki AsyncTask nie zakończy pracy w wątku w tle. Jeśli działanie zostanie zakończone lub zabite przed zakończeniem pracy wątku AsyncTask w tle, AsyncTask nadal będzie mieć odniesienie do działania, a zatem nie będzie można go wyrzucać.
W rezultacie spowoduje to wyciek pamięci.
Aby temu zapobiec, użyj WeakReference w AsyncTask zamiast bezpośredniego odniesienia do działania.
Oto przykład AsyncTask wykorzystujący WeakReference:
private class MyAsyncTask extends AsyncTask<String, Void, Void> {
private WeakReference<Activity> mActivity;
public MyAsyncTask(Activity activity) {
mActivity = new WeakReference<Activity>(activity);
}
@Override
protected void onPreExecute() {
final Activity activity = mActivity.get();
if (activity != null) {
....
}
}
@Override
protected Void doInBackground(String... params) {
//Do something
String param1 = params[0];
String param2 = params[1];
return null;
}
@Override
protected void onPostExecute(Void result) {
final Activity activity = mActivity.get();
if (activity != null) {
activity.updateUI();
}
}
}
Wywoływanie zadania AsyncTask z działania:
new MyAsyncTask(this).execute("param1", "param2");
Wywoływanie AsyncTask z fragmentu:
new MyAsyncTask(getActivity()).execute("param1", "param2");
Kolejność wykonania
Po raz pierwszy AsyncTasks
były wykonywane szeregowo w jednym wątku w tle. Począwszy od DONUT
, zmieniono to na pulę wątków, umożliwiając równoległe wykonywanie wielu zadań. Począwszy od HONEYCOMB
, zadania są wykonywane w jednym wątku, aby uniknąć typowych błędów aplikacji spowodowanych równoległym wykonywaniem.
Jeśli naprawdę chcesz wykonywać równolegle, możesz wywołać executeOnExecutor(java.util.concurrent.Executor, Object[])
pomocą THREAD_POOL_EXECUTOR
.
SERIAL_EXECUTOR -> Executor wykonujący zadania pojedynczo w kolejności szeregowej.
THREAD_POOL_EXECUTOR -> Executor, którego można używać do równoległego wykonywania zadań.
próbka:
Task task = new Task();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, data);
else
task.execute(data);
AsyncTask: wykonanie szeregowe i równoległe wykonanie zadania
AsyncTask jest klasą abstrakcyjną i nie dziedziczy klasy Thread
. Ma abstrakcyjną metodę doInBackground(Params... params)
, która jest nadpisywana w celu wykonania zadania. Ta metoda jest wywoływana z AsyncTask.call()
.
Moduł wykonujący jest częścią pakietu java.util.concurrent
.
Ponadto AsyncTask zawiera 2 Executor
THREAD_POOL_EXECUTOR
Używa wątków roboczych do równoległego wykonywania zadań.
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
SERIAL_EXECUTOR
Wykonuje zadanie szeregowo, tzn. Jeden po drugim.
private static class SerialExecutor implements Executor { }
Oba moduły Executor
są statyczne , dlatego istnieje tylko jeden obiekt THREAD_POOL_EXECUTOR
i jeden obiekt SerialExecutor
, ale można utworzyć kilka obiektów AsyncTask
.
Dlatego jeśli spróbujesz wykonać wiele zadań w tle przy użyciu domyślnego SerialExecutor
( SerialExecutor
), zadanie to zostanie umieszczone w kolejce i wykonane szeregowo.
Jeśli spróbujesz wykonać wiele zadań w tle za pomocą THREAD_POOL_EXECUTOR
, zostaną one wykonane równolegle.
Przykład:
public class MainActivity extends Activity {
private Button bt;
private int CountTask = 0;
private static final String TAG = "AsyncTaskExample";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = (Button) findViewById(R.id.button);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
BackgroundTask backgroundTask = new BackgroundTask ();
Integer data[] = { ++CountTask, null, null };
// Task Executed in thread pool ( 1 )
backgroundTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, data);
// Task executed Serially ( 2 )
// Uncomment the below code and comment the above code of Thread
// pool Executor and check
// backgroundTask.execute(data);
Log.d(TAG, "Task = " + (int) CountTask + " Task Queued");
}
});
}
private class BackgroundTask extends AsyncTask<Integer, Integer, Integer> {
int taskNumber;
@Override
protected Integer doInBackground(Integer... integers) {
taskNumber = integers[0];
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d(TAG, "Task = " + taskNumber + " Task Running in Background");
publishProgress(taskNumber);
return null;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(Integer aLong) {
super.onPostExecute(aLong);
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.d(TAG, "Task = " + (int) values[0]
+ " Task Execution Completed");
}
}
}
Wykonaj Kliknij kilka razy przycisk, aby rozpocząć zadanie i zobaczyć wynik.
Zadanie wykonane w puli wątków (1)
Każde zadanie zajmuje 1000 ms.
W czasie t = 36s zadania 2, 3 i 4 są umieszczone w kolejce i rozpoczęły wykonywanie również dlatego, że są wykonywane równolegle.
08-02 19:48:35.815: D/AsyncTaskExample(11693): Task = 1 Task Queued
08-02 19:48:35.815: D/AsyncTaskExample(11693): Task = 1 Task Running in Background
08-02 19:48:**36.025**: D/AsyncTaskExample(11693): Task = 2 Task Queued
08-02 19:48:**36.025**: D/AsyncTaskExample(11693): Task = 2 Task Running in Background
08-02 19:48:**36.165**: D/AsyncTaskExample(11693): Task = 3 Task Queued
08-02 19:48:**36.165**: D/AsyncTaskExample(11693): Task = 3 Task Running in Background
08-02 19:48:**36.325**: D/AsyncTaskExample(11693): Task = 4 Task Queued
08-02 19:48:**36.325**: D/AsyncTaskExample(11693): Task = 4 Task Running in Background
08-02 19:48:**36.815**: D/AsyncTaskExample(11693): Task = 1 Task Execution Completed
08-02 19:48:**36.915**: D/AsyncTaskExample(11693): Task = 5 Task Queued
08-02 19:48:**36.915**: D/AsyncTaskExample(11693): Task = 5 Task Running in Background
08-02 19:48:37.025: D/AsyncTaskExample(11693): Task = 2 Task Execution Completed
08-02 19:48:37.165: D/AsyncTaskExample(11693): Task = 3 Task Execution Completed
----------
Komentarz Task Executed in thread pool
(1) i odkomentowanie Task executed Serially
(2).
Wykonaj Kliknij kilka razy przycisk, aby rozpocząć zadanie i zobaczyć wynik.
Wykonuje zadanie szeregowo, dlatego każde zadanie jest uruchamiane po zakończeniu bieżącego zadania. Dlatego po zakończeniu wykonywania zadania 1 tylko zadanie 2 zaczyna działać w tle. Nawzajem.
08-02 19:42:57.505: D/AsyncTaskExample(10299): Task = 1 Task Queued
08-02 19:42:57.505: D/AsyncTaskExample(10299): Task = 1 Task Running in Background
08-02 19:42:57.675: D/AsyncTaskExample(10299): Task = 2 Task Queued
08-02 19:42:57.835: D/AsyncTaskExample(10299): Task = 3 Task Queued
08-02 19:42:58.005: D/AsyncTaskExample(10299): Task = 4 Task Queued
08-02 19:42:58.155: D/AsyncTaskExample(10299): Task = 5 Task Queued
08-02 19:42:58.505: D/AsyncTaskExample(10299): Task = 1 Task Execution Completed
08-02 19:42:58.505: D/AsyncTaskExample(10299): Task = 2 Task Running in Background
08-02 19:42:58.755: D/AsyncTaskExample(10299): Task = 6 Task Queued
08-02 19:42:59.295: D/AsyncTaskExample(10299): Task = 7 Task Queued
08-02 19:42:59.505: D/AsyncTaskExample(10299): Task = 2 Task Execution Completed
08-02 19:42:59.505: D/AsyncTaskExample(10299): Task = 3 Task Running in Background
08-02 19:43:00.035: D/AsyncTaskExample(10299): Task = 8 Task Queued
08-02 19:43:00.505: D/AsyncTaskExample(10299): Task = 3 Task Execution Completed
08-02 19:43:**00.505**: D/AsyncTaskExample(10299): Task = 4 Task Running in Background
08-02 19:43:**01.505**: D/AsyncTaskExample(10299): Task = 4 Task Execution Completed
08-02 19:43:**01.515**: D/AsyncTaskExample(10299): Task = 5 Task Running in Background
08-02 19:43:**02.515**: D/AsyncTaskExample(10299): Task = 5 Task Execution Completed
08-02 19:43:**02.515**: D/AsyncTaskExample(10299): Task = 6 Task Running in Background
08-02 19:43:**03.515**: D/AsyncTaskExample(10299): Task = 7 Task Running in Background
08-02 19:43:**03.515**: D/AsyncTaskExample(10299): Task = 6 Task Execution Completed
08-02 19:43:04.515: D/AsyncTaskExample(10299): Task = 8 Task Running in Background
08-02 19:43:**04.515**: D/AsyncTaskExample(10299): Task = 7 Task Execution Completed