Android
AsyncTask
Zoeken…
parameters
Parameter | Details |
---|---|
params | het type parameters dat bij uitvoering naar de taak wordt verzonden. |
Vooruitgang | het type voortgangseenheden dat tijdens de achtergrondberekening is gepubliceerd |
Resultaat | het type resultaat van de achtergrondberekening. |
Basisgebruik
In Android Activiteiten en Services , zijn de meeste callbacks draaien op de rode draad . Dit maakt het eenvoudig om de gebruikersinterface bij te werken, maar het uitvoeren van processor- of I / O-zware taken op de hoofdthread kan ervoor zorgen dat uw gebruikersinterface pauzeert en niet meer reageert ( officiële documentatie over wat er dan gebeurt).
U kunt dit verhelpen door deze zwaardere taken op een achtergrondthread te plaatsen.
Een manier om dit te doen is het gebruik van een AsyncTask , dat een raamwerk biedt om eenvoudig gebruik te maken van een achtergrondthread en ook UI-threadtaken uit te voeren voordat, tijdens en nadat de achtergrondthread zijn werk heeft voltooid.
Methoden die kunnen worden opgeheven bij het uitbreiden van AsyncTask
:
-
onPreExecute()
: aangeroepen op de UI-thread voordat de taak wordt uitgevoerd -
doInBackground()
: aangeroepen op de achtergrondthread onmiddellijk nadatonPreExecute()
is uitgevoerd. -
onProgressUpdate()
: aangeroepen in de UI-thread na een oproep ompublishProgress(Progress...)
tepublishProgress(Progress...)
. -
onPostExecute()
: aangeroepen op de UI-thread nadat de achtergrondberekening is voltooid
Voorbeeld
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.");
}
}
}
Gebruik:
MyCustomAsyncTask asyncTask = new MyCustomAsyncTask<File, Void, String>();
// Run the task with a user supplied filename.
asyncTask.execute(userSuppliedFilename);
of gewoon:
new MyCustomAsyncTask().execute(userSuppliedFilename);
Notitie
Bij het definiëren van een AsyncTask
we drie typen tussen < >
haakjes doorgeven.
Gedefinieerd als <Params, Progress, Result>
(zie paragraaf Parameters )
In het vorige voorbeeld hebben we types <File, Void, String>
:
AsyncTask<File, Void, String>
// Params has type File
// Progress has unused type
// Result has type String
Void
wordt gebruikt wanneer u een type als ongebruikt wilt markeren.
Merk op dat u geen primitieve typen (dwz int
, float
en 6 andere) als parameters kunt doorgeven. In dergelijke gevallen moet u hun wrapper-klassen doorgeven, bijvoorbeeld Integer
plaats van int
of Float
plaats van float
.
De levenscyclus van AsyncTask en activiteit
AsyncTasks volgen de levenscyclus van activiteitsinstances niet. Als u een AsyncTask binnen een activiteit start en u het apparaat roteert, wordt de activiteit vernietigd en wordt een nieuwe instantie gemaakt. Maar de AsyncTask zal niet sterven. Het zal blijven leven totdat het voltooid is.
Oplossing: AsyncTaskLoader
Een subklasse van laders is de AsyncTaskLoader. Deze klasse heeft dezelfde functie als de AsyncTask, maar veel beter. Het kan wijzigingen in de activiteitsconfiguratie gemakkelijker verwerken en het gedraagt zich binnen de levenscycli van Fragmenten en Activiteiten. Het leuke is dat de AsyncTaskLoader kan worden gebruikt in elke situatie waarin de AsyncTask wordt gebruikt. Telkens wanneer gegevens in het geheugen moeten worden geladen om de activiteit / het fragment te kunnen verwerken, kan de AsyncTaskLoader het werk beter doen.
AsyncTask annuleren
YourAsyncTask task = new YourAsyncTask();
task.execute();
task.cancel();
Dit stopt uw taak niet als deze aan de gang was, maar stelt gewoon de geannuleerde vlag in die kan worden gecontroleerd door de retourwaarde van isCancelled()
(ervan uitgaande dat uw code momenteel actief is):
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;
}
}
}
}
Notitie
Als een AsyncTask wordt geannuleerd terwijl doInBackground(Params... params)
nog steeds wordt uitgevoerd, wordt de methode onPostExecute(Result result)
NIET aangeroepen nadat doInBackground(Params... params)
geretourneerd. De AsyncTask roept in plaats daarvan het onCancelled(Result result)
aan om aan te geven dat de taak tijdens de uitvoering is geannuleerd.
Publicatievoortgang
Soms moeten we de voortgang van de berekening bijwerken die is uitgevoerd door een AsyncTask
. Deze voortgang kan worden voorgesteld door een string, een geheel getal, enz. Om dit te doen, moeten we twee functies gebruiken. Eerst moeten we de functie onProgressUpdate
waarvan het parametertype hetzelfde is als de parameter van het tweede type van onze AsyncTask
.
class YourAsyncTask extends AsyncTask<URL, Integer, Long> {
@Override
protected void onProgressUpdate(Integer... args) {
setProgressPercent(args[0])
}
}
Ten tweede moeten we de functie publishProgress
noodzakelijkerwijs gebruiken voor de functie publishProgress
, en dat is alles, de vorige methode doInBackground
.
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;
}
Afbeelding downloaden met AsyncTask in Android
In deze zelfstudie wordt uitgelegd hoe u Afbeelding kunt downloaden met AsyncTask in Android. Het onderstaande voorbeeld download afbeelding terwijl de voortgangsbalk wordt getoond tijdens het downloaden.
Inzicht in Android AsyncTask
Met de Async-taak kunt u MultiThreading implementeren zonder uw handen vuil te maken in threads. AsyncTask maakt correct en gemakkelijk gebruik van de UI-thread mogelijk. Hiermee kunt u achtergrondbewerkingen uitvoeren en de resultaten doorgeven aan de UI-thread. Als u iets geïsoleerds aan de gebruikersinterface doet, bijvoorbeeld gegevens downloadt om in een lijst weer te geven, ga dan door en gebruik AsyncTask.- AsyncTasks zou idealiter moeten worden gebruikt voor korte operaties (maximaal enkele seconden).
- Een asynchrone taak wordt gedefinieerd door 3 generieke typen, genaamd Params, Progress en Result, en 4 stappen, genaamd
onPreExecute()
,doInBackground()
,onProgressUpdate()
enonPostExecute()
. - In
onPreExecute()
kunt u code definiëren, die moet worden uitgevoerd voordat de achtergrondverwerking begint. - doInBackground heeft code die op de achtergrond moet worden uitgevoerd, hier in
doInBackground()
we resultaten meerdere keren naar de evenementendraad sturen via de methode publishProgress (), om te melden dat de achtergrondverwerking is voltooid, kunnen we eenvoudig resultaten retourneren. -
onProgressUpdate()
methodeonProgressUpdate()
ontvangt voortgangsupdates van de methodedoInBackground()
, die wordt gepubliceerd via de methodepublishProgress()
, en deze methode kan deze voortgangsupdate gebruiken om gebeurtenisthread bij te werken - methode
onPostExecute()
verwerkt resultaten die worden geretourneerd door de methodedoInBackground()
. - De gebruikte generieke typen zijn
- Params, het type parameters dat bij uitvoering naar de taak wordt verzonden
- Voortgang, het type voortgangseenheden dat tijdens de achtergrondberekening is gepubliceerd.
- Resultaat, het type resultaat van de achtergrondberekening.
- Als een asynchrone taak geen typen gebruikt, kan deze worden gemarkeerd als Type ongeldig.
- Een actieve async-taak kan worden geannuleerd door de methode
cancel(boolean)
aan te roepen.
Afbeelding downloaden met Android AsyncTask
uw .xml-indeling
<?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>
.java-klasse
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;
}
}
}
Aangezien er momenteel geen commentaarveld is voor voorbeelden (of ik heb het niet gevonden of ik heb er geen toestemming voor), is hier enige commentaar hierover:
Dit is een goed voorbeeld van wat er met AsyncTask kan worden gedaan.
Het voorbeeld heeft momenteel echter problemen met
- mogelijke geheugenlekken
- app crasht als er een schermrotatie was kort voordat de async-taak was voltooid.
Voor details zie:
- Geef activiteit door als WeakReference om geheugenlekken te voorkomen
- http://stackoverflow.com/documentation/android/117/asynctask/5377/possible-problems-with-inner-async-tasks
- Vermijd lekkende activiteiten met AsyncTask
Geef activiteit door als WeakReference om geheugenlekken te voorkomen
Het is gebruikelijk dat een AsyncTask een verwijzing vereist naar de activiteit die deze heeft aangeroepen.
Als de AsyncTask een binnenklasse van de activiteit is, kunt u hiernaar en alle lidvariabelen / methoden direct verwijzen.
Als de AsyncTask echter geen binnenklasse van de activiteit is, moet u een activiteitsreferentie aan de AsyncTask doorgeven. Wanneer u dit doet, is een mogelijk probleem dat zich kan voordoen, dat de AsyncTask de referentie van de activiteit behoudt totdat de AsyncTask zijn werk in de achtergrondthread heeft voltooid. Als de activiteit is voltooid of gedood voordat het achtergronddraadwerk van de AsyncTask is voltooid, heeft de AsyncTask nog steeds een verwijzing naar de activiteit en kan deze daarom niet worden verzameld.
Hierdoor zal een geheugenlek ontstaan.
Om dit te voorkomen, gebruikt u een WeakReference in de AsyncTask in plaats van een directe verwijzing naar de activiteit.
Hier is een voorbeeld van AsyncTask dat een WeakReference gebruikt:
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();
}
}
}
De AsyncTask oproepen vanuit een activiteit:
new MyAsyncTask(this).execute("param1", "param2");
De AsyncTask uit een fragment oproepen:
new MyAsyncTask(getActivity()).execute("param1", "param2");
Volgorde van uitvoering
Toen het voor het eerst werd geïntroduceerd, werden AsyncTasks
serieel uitgevoerd op een enkele achtergrondthread. Beginnend met DONUT
werd dit veranderd in een pool van threads waardoor meerdere taken parallel konden werken. Beginnend met HONEYCOMB
worden taken uitgevoerd op een enkele thread om veelvoorkomende applicatiefouten veroorzaakt door parallelle uitvoering te voorkomen.
Als je echt parallelle uitvoering wilt, kun je executeOnExecutor(java.util.concurrent.Executor, Object[])
THREAD_POOL_EXECUTOR
met THREAD_POOL_EXECUTOR
.
SERIAL_EXECUTOR -> Een uitvoerder die taken één voor één in seriële volgorde uitvoert.
THREAD_POOL_EXECUTOR -> Een uitvoerder die kan worden gebruikt om taken parallel uit te voeren.
voorbeeld:
Task task = new Task();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, data);
else
task.execute(data);
AsyncTask: seriële uitvoering en parallelle uitvoering van taak
AsyncTask is een abstracte klasse en neemt de Thread
klasse niet over. Het heeft een abstracte methode doInBackground(Params... params)
, die wordt overschreven om de taak uit te voeren. Deze methode wordt aangeroepen vanuit AsyncTask.call()
.
Executor maakt deel uit van java.util.concurrent
pakket.
Bovendien bevat AsyncTask 2 Executor
THREAD_POOL_EXECUTOR
Het gebruikt werkdraden om de taken parallel uit te voeren.
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
SERIAL_EXECUTOR
Het voert de taak serieel uit, dwz één voor één.
private static class SerialExecutor implements Executor { }
Beide Executor
zijn statisch , vandaar dat er slechts één THREAD_POOL_EXECUTOR
en één SerialExecutor
objecten bestaan, maar u kunt verschillende AsyncTask
objecten maken.
Als u daarom meerdere achtergrondtaken probeert uit te voeren met de standaarduitvoerder ( SerialExecutor
), worden deze taken in de wachtrij geplaatst en serieel uitgevoerd.
Als u probeert meerdere achtergrondtaken uit te voeren met THREAD_POOL_EXECUTOR
, dan worden ze parallel uitgevoerd.
Voorbeeld:
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");
}
}
}
Uitvoeren Klik meerdere keren op de knop om een taak te starten en het resultaat te bekijken.
Taak uitgevoerd in thread pool (1)
Elke taak duurt 1000 ms om te voltooien.
Op t = 36s worden taken 2, 3 en 4 in de wachtrij geplaatst en worden ze ook uitgevoerd omdat ze parallel worden uitgevoerd.
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
----------
Task Executed in thread pool
(1) en niet-reagerende Task executed Serially
(2).
Uitvoeren Klik meerdere keren op de knop om een taak te starten en het resultaat te bekijken.
Het voert de taak serieel uit, vandaar dat elke taak wordt gestart nadat de huidige taak is uitgevoerd. Wanneer de uitvoering van taak 1 is voltooid, wordt alleen taak 2 op de achtergrond uitgevoerd. Vice versa.
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