Android
AsyncTask
Sök…
parametrar
Parameter | detaljer |
---|---|
params | typen av parametrar som skickas till uppgiften vid körning. |
Framsteg | vilken typ av framstegsenheter som publicerades under bakgrundsberäkningen |
Resultat | typen av resultatet av bakgrundsberäkningen. |
Grundläggande användning
I Android- aktiviteter och tjänster körs de flesta återuppringningar på huvudtråden . Detta gör det enkelt att uppdatera användargränssnittet, men att köra processor- eller I / O-tunga uppgifter på huvudtråden kan få din UI att pausa och bli svarsfri ( officiell dokumentation om vad som sedan händer).
Du kan avhjälpa detta genom att lägga dessa tyngre uppgifter på en bakgrundstråd.
Ett sätt att göra detta är att använda en AsyncTask , som ger ett ramverk för att underlätta enkel användning av en bakgrundstråd, och även utföra UI-tråduppgifter före, under och efter bakgrunden Tråden har slutfört sitt arbete.
Metoder som kan åsidosättas vid AsyncTask
:
-
onPreExecute()
: aktiveras på UI-tråden innan uppgiften körs -
doInBackground()
: åberopas på bakgrundstråden omedelbart efter attonPreExecute()
avslutats. -
onProgressUpdate()
: åberopas på UI-tråden efter ett samtal attpublishProgress(Progress...)
. -
onPostExecute()
: startas på UI-tråden efter att bakgrundsberäkningen är klar
Exempel
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.");
}
}
}
Användande:
MyCustomAsyncTask asyncTask = new MyCustomAsyncTask<File, Void, String>();
// Run the task with a user supplied filename.
asyncTask.execute(userSuppliedFilename);
eller bara:
new MyCustomAsyncTask().execute(userSuppliedFilename);
Notera
När vi definierar en AsyncTask
vi passera tre typer mellan < >
parentes.
Definierat som <Params, Progress, Result>
(se avsnittet Parametrar )
I föregående exempel har vi använt typerna <File, Void, String>
:
AsyncTask<File, Void, String>
// Params has type File
// Progress has unused type
// Result has type String
Void
används när du vill markera en typ som oanvänd.
Observera att du inte kan skicka primitiva typer (dvs. int
, float
och 6 andra) som parametrar. I sådana fall bör du passera deras omslagsklasser , t.ex. Integer
istället för int
, eller Float
istället för float
.
Livscykeln AsyncTask och Activity
AsyncTasks följer inte aktivitetsinstansers livscykel. Om du startar en AsyncTask i en aktivitet och du roterar enheten kommer aktiviteten att förstöras och en ny instans skapas. Men AsyncTask kommer inte att dö. Den kommer att leva tills den är klar.
Lösning: AsyncTaskLoader
En underklass av Loaders är AsyncTaskLoader. Den här klassen utför samma funktion som AsyncTask, men mycket bättre. Den kan hantera förändringar av aktivitetskonfigurationen lättare och fungerar inom livscyklerna för fragment och aktiviteter. Det trevliga är att AsyncTaskLoader kan användas i alla situationer som AsyncTask används. När som helst data måste laddas i minnet för att Aktiviteten / Fragmentet ska kunna hanteras. AsyncTaskLoader kan göra jobbet bättre.
Avbryter AsyncTask
YourAsyncTask task = new YourAsyncTask();
task.execute();
task.cancel();
Detta stoppar inte din uppgift om den pågick, den ställer bara in den avbrutna flaggan som kan kontrolleras genom att kontrollera returvärdet för isCancelled()
(förutsatt att din kod för närvarande körs) genom att göra detta:
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;
}
}
}
}
Notera
Om en AsyncTask avbryts medan doInBackground(Params... params)
fortfarande körs, kommer metoden onPostExecute(Result result)
INTE att kallas efter att doInBackground(Params... params)
kommer tillbaka. AsyncTask kommer istället att ringa onCancelled(Result result)
att indikera att uppgiften avbröts under körningen.
Publiceringsframsteg
Ibland måste vi uppdatera framstegen för beräkningen som görs av en AsyncTask
. Denna framsteg kan representeras av en sträng, ett heltal osv. För att göra detta måste vi använda två funktioner. Först måste vi ställa onProgressUpdate
funktionen onProgressUpdate
vars parametertyp är densamma som den andra AsyncTask
vår AsyncTask
.
class YourAsyncTask extends AsyncTask<URL, Integer, Long> {
@Override
protected void onProgressUpdate(Integer... args) {
setProgressPercent(args[0])
}
}
För det andra måste vi använda funktionen publishProgress
nödvändigtvis på doInBackground
funktionen, och det är allt, den tidigare metoden kommer att göra allt jobbet.
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;
}
Ladda ner bild med AsyncTask i Android
Denna handledning förklarar hur du laddar ner bild med AsyncTask i Android. Exemplet nedladdningsbild medan du visar framstegsfältet under nedladdningen.
Förstå Android AsyncTask
Med Async-uppgiften kan du implementera MultiThreading utan att få Händerna smutsiga i trådar. AsyncTask möjliggör korrekt och enkel användning av UI-tråden. Det gör det möjligt att utföra bakgrundsoperationer och skicka resultaten på UI-tråden. Om du gör något isolerat relaterat till UI, till exempel nedladdning av data för att presenteras i en lista, gå vidare och använd AsyncTask.- AsyncTasks bör helst användas för korta operationer (högst några sekunder.)
- En asynkron uppgift definieras av 3 generiska typer, kallad Params, Progress and Result, och fyra steg, som kallas
onPreExecute()
,doInBackground()
,onProgressUpdate()
ochonPostExecute()
. - I
onPreExecute()
du definiera kod som måste köras innan bakgrundsbearbetningen startar. - doInBackground har kod som måste utföras i bakgrunden, här i
doInBackground()
vi skicka resultat till flera gånger till händelsetråd med metoden publicProgress (), för att meddela att bakgrundsbearbetningen har avslutats kan vi returnera resultaten helt enkelt. -
onProgressUpdate()
får framstegsuppdateringar fråndoInBackground()
, som publiceras viapublishProgress()
, och den här metoden kan använda denna framstegsuppdatering för att uppdatera händelsetråd -
onPostExecute()
hanterar resultat som returnerats meddoInBackground()
. - De generiska typerna som används är
- Params, typen av parametrar som skickas till uppgiften vid körning
- Framsteg, vilken typ av framstegsenheter som publicerades under bakgrundsberäkningen.
- Resultat, typen av resultatet för bakgrundsberäkningen.
- Om en async-uppgift inte använder några typer kan den markeras som Void-typ.
- En löpande async-uppgift kan avbrytas genom att anropa
cancel(boolean)
metod.
Nedladdning av bild med Android AsyncTask
din .xml-layout
<?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 klass
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;
}
}
}
Eftersom det för närvarande inte finns något kommentarfält för exempel (eller jag inte har hittat det eller jag inte har behörighet för det) är här några kommentarer om detta:
Detta är ett bra exempel på vad som kan göras med AsyncTask.
Men exemplet har för närvarande problem med
- möjliga minnesläckor
- app-krasch om det fanns en skärmrotation strax innan async-uppgiften avslutades.
För detaljer se:
- Vidarebefordra aktivitet som WeakReference för att undvika minnesläckor
- http://stackoverflow.com/documentation/android/117/asynctask/5377/possible-problems-with-inner-async-tasks
- Undvik att läcka aktiviteter med AsyncTask
Passera aktivitet som WeakReference för att undvika minnesläckor
Det är vanligt att en AsyncTask kräver en hänvisning till den aktivitet som kallade den.
Om AsyncTask är en inre klass i aktiviteten, kan du referera till den och eventuella medlemsvariabler / metoder direkt.
Om AsyncTask emellertid inte är en inre klass i aktiviteten måste du skicka en aktivitetsreferens till AsyncTask. När du gör detta är ett potentiellt problem som kan uppstå att AsyncTask behåller referensen till aktiviteten tills AsyncTask har avslutat sitt arbete i sin bakgrundstråd. Om aktiviteten är klar eller dödas innan AsyncTasks bakgrundsgängarbetet är gjort, kommer AsyncTask fortfarande att ha sin referens till aktiviteten, och därför kan den inte samlas in.
Som ett resultat kommer detta att leda till ett minnesläckage.
Använd en WeakReference i AsyncTask istället för att direkt hänvisa till aktiviteten för att förhindra att detta sker.
Här är ett exempel på AsyncTask som använder en 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();
}
}
}
Ringa AsyncTask från en aktivitet:
new MyAsyncTask(this).execute("param1", "param2");
Ringa AsyncTask från ett fragment:
new MyAsyncTask(getActivity()).execute("param1", "param2");
Bekräftelse av utförande
Vid första introduktionen AsyncTasks
seriellt på en enda bakgrundstråd. Från och med DONUT
ändrades detta till en pool av trådar som tillåter flera uppgifter att fungera parallellt. Från och med HONEYCOMB
uppgifter på en enda tråd för att undvika vanliga applikationsfel orsakade av parallellkörning.
Om du verkligen vill ha parallellkörning kan du åberopa executeOnExecutor(java.util.concurrent.Executor, Object[])
med THREAD_POOL_EXECUTOR
.
SERIAL_EXECUTOR -> En Executor som utför uppgifter en i taget i serieordning.
THREAD_POOL_EXECUTOR -> En kör som kan användas för att utföra uppgifter parallellt.
prov:
Task task = new Task();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, data);
else
task.execute(data);
AsyncTask: Seriell exekvering och parallell exekvering av uppgift
AsyncTask är en abstrakt klass och ärver inte Thread
. Den har en abstrakt metod doInBackground(Params... params)
, som åsidosätts för att utföra uppgiften. Den här metoden kallas från AsyncTask.call()
.
Executor ingår i java.util.concurrent
paketet.
Dessutom innehåller AsyncTask 2 Executor
s
THREAD_POOL_EXECUTOR
Den använder arbetartrådar för att utföra uppgifterna parallellt.
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
SERIAL_EXECUTOR
Den utför uppgiften seriellt, dvs en efter en.
private static class SerialExecutor implements Executor { }
Båda Executor
s är statiska , varför endast ett THREAD_POOL_EXECUTOR
och ett SerialExecutor
objekt finns, men du kan skapa flera AsyncTask
objekt.
Om du försöker göra flera bakgrundsuppgifter med standardexekutorn ( SerialExecutor
) kommer dessa uppgifter att stå i kö och körs seriellt.
Om du försöker göra flera bakgrundsuppgifter med THREAD_POOL_EXECUTOR
, kommer de att köras parallellt.
Exempel:
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");
}
}
}
Utför Klicka på knappen flera gånger för att starta en uppgift och se resultatet.
Uppgift utförd i trådpool (1)
Varje uppgift tar 1000 ms att slutföra.
Vid t = 36s står uppgifterna 2, 3 och 4 i kö och började köras också för att de körs parallellt.
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
----------
Kommentar Task Executed in thread pool
(1) och avdelning Task executed Serially
(2).
Utför Klicka på knappen flera gånger för att starta en uppgift och se resultatet.
Den kör serien seriellt, varför varje uppgift startas efter den aktuella utförda uppgiften. Därför när exekvering av uppgift 1 är klar, börjar bara uppgift 2 köras i bakgrunden. 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