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 nadat onPreExecute() is uitgevoerd.
  • onProgressUpdate() : aangeroepen in de UI-thread na een oproep om publishProgress(Progress...) te publishProgress(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() en onPostExecute() .
  • 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() methode onProgressUpdate() ontvangt voortgangsupdates van de methode doInBackground() , die wordt gepubliceerd via de methode publishProgress() , en deze methode kan deze voortgangsupdate gebruiken om gebeurtenisthread bij te werken
  • methode onPostExecute() verwerkt resultaten die worden geretourneerd door de methode doInBackground() .
  • 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

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


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow