Frage

Ich versuche, zwei AsyncTasks zur gleichen Zeit ausgeführt werden. (Platform ist Android 1.5, HTC Hero.) Jedoch nur die erste wird ausgeführt. Hier ist ein einfaches Snippet mein Problem zu beschreiben:

public class AndroidJunk extends Activity {
 class PrinterTask extends AsyncTask<String, Void, Void> {
     protected Void doInBackground(String ... x) {
      while (true) {
       System.out.println(x[0]);
       try {
        Thread.sleep(1000);
       } catch (InterruptedException ie) {
        ie.printStackTrace();
       }
      }
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        new PrinterTask().execute("bar bar bar");
        new PrinterTask().execute("foo foo foo");

        System.out.println("onCreate() is done.");
    }
}

Der Ausgang I erwarten ist:

onCreate() is done.
bar bar bar
foo foo foo
bar bar bar
foo foo foo

Und so weiter. Doch was ich erhalte, ist:

onCreate() is done.
bar bar bar
bar bar bar
bar bar bar

Die zweite AsyncTask wird nie ausgeführt. Wenn ich die Reihenfolge der () Anweisungen ausführen ändern, nur die foo Aufgabe Ausgabe erzeugen wird.

Bin ich etwas fehlt hier offensichtlich und / oder etwas zu tun dumm? Ist es nicht möglich, zwei AsyncTasks gleichzeitig laufen zu lassen?

Edit: ich das Telefon in Frage realisiert läuft Android 1.5, habe ich das Problem Beschr aktualisiert. entsprechend. Ich habe nicht dieses Problem mit einem HTC Hero mit Android 2.1. Hmmm ...

War es hilfreich?

Lösung

AsyncTask verwendet ein Thread-Pool-Muster für das Material von doInBackground läuft (). Die Frage ist zunächst (in frühen Android OS-Versionen) die Poolgröße war nur 1, keine parallelen Berechnungen für eine Reihe von AsyncTasks Bedeutung. Aber später werden sie festgelegt, dass nun die Größe ist 5, so höchstens 5 AsyncTasks gleichzeitig ausgeführt werden können. Leider gibt es in weiß ich nicht mehr, was Version genau, dass sie geändert werden.

UPDATE:

Hier ist, was Strom (2012-01-27) API sagt dazu:

  

Wenn zuerst eingeführt, AsyncTasks wurden seriell auf einem einzigen Hintergrund-Thread ausgeführt wird. Beginnend mit DOUGHNUT wurde dieser auf einen Pool von Threads geändert, um mehrere Aufgaben parallel zu betreiben. Nach BIENENWABE ist geplant, diese wieder zu einem einzigen Thread zu ändern gemeinsame Anwendungsfehler durch parallele Ausführung zu vermeiden. Wenn Sie wirklich parallele Ausführung möchten, können Sie die executeOnExecutor (Executor, Params ...) verwenden Version dieses Verfahrens mit THREAD_POOL_EXECUTOR; siehe Erläuterungen gibt es jedoch für Warnhinweise bezüglich der Benutzung.

DONUT ist Android 1.6, ist BIENENWABE Android 3.0.

UPDATE: 2

Siehe Kommentar von kabuko von Mar 7 at 1:27.

Es stellt sich heraus, dass für APIs, wo „ein Pool von Threads ermöglicht, mehrere Aufgaben parallel zu betreiben“ verwendet wird (von 1,6 und endend auf 3,0), die Anzahl der gleichzeitig laufenden AsyncTasks hängt davon ab, wie viele Aufgaben haben, zur Ausführung übergeben worden schon, aber haben ihre doInBackground() noch nicht fertig.

Dies wird getestet / von mir bestätigt auf 2.2. Angenommen, Sie eine benutzerdefinierte AsyncTask haben, die nur eine Sekunde in doInBackground() schläft. AsyncTasks verwenden, um eine Warteschlange fester Grße intern verzögerte Aufgaben speichert. Warteschlangengröße beträgt 10 voreingestellt. Wenn Sie 15 Ihre benutzerdefinierten Aufgaben in einer Reihe zu starten, dann zunächst 5 ihre doInBackground() geben, aber der Rest wird für einen freien Arbeitsthread in einer Warteschlange warten. Sobald eine der ersten 5 beendet ist, und somit einen Arbeiter-Thread freigibt, wird eine Aufgabe aus der Warteschlange der Ausführung beginnen. Also in diesem Fall höchstens 5 Aufgaben gleichzeitig ausgeführt werden. Wenn Sie jedoch 16 Ihre benutzerdefinierten Aufgaben in einer Reihe starten, dann zunächst 5 ihre doInBackground() eingeben, der Rest 10 wird in die Warteschlange, aber für die 16. ein neuen Arbeitsthread erstellt werden, damit es der Ausführung sofort beginnen werde. Also in diesem Fall höchstens 6 Aufgaben gleichzeitig ausgeführt werden.

Es gibt eine Grenze, wie viele Aufgaben gleichzeitig ausgeführt werden. Da AsyncTask verwendet einen Thread-Pool Testamentsvollstrecker mit begrenzt max Anzahl der Arbeitsthreads (128) und die verzögerten Aufgaben hat Warteschlangengröße 10 festgelegt, wenn Sie mehr als 138 Ihre benutzerdefinierte Aufgaben auszuführen versuchen, stürzt die App mit java.util.concurrent.RejectedExecutionException.

3,0 Starten des API ermöglicht Ihren benutzerdefinierten Thread-Pool Testamentsvollstrecker über AsyncTask.executeOnExecutor(Executor exec, Params... params) Methode zu verwenden. Dies ermöglicht zum Beispiel die Größe der verzögerten Aufgaben zu konfigurieren Warteschlange, wenn Standard-10 ist nicht das, was Sie brauchen.

Wie @Knossos erwähnt, gibt es eine Option zur Verwendung AsyncTaskCompat.executeParallel(task, params); von Unterstützung v.4 Bibliothek Aufgaben parallel ausführen, ohne mit API-Ebene stört. Diese Methode wurde in API-Ebene veraltet 26.0.0.

UPDATE: 3

Hier ist ein einfacher Test-App mit der Anzahl der Aufgaben, Serien vs. parallele Ausführung zu spielen: https: // Github .com / vitkhudenko / test_asynctask

UPDATE: 4 (dank @penkzhou für diesen Hinweis)

Ab Android 4.4 AsyncTask verhält sich anders, als es in UPDATE beschrieben wurde: 2 . Es ist ein fix zu verhindern AsyncTask aus zu viele Threads zu schaffen.

Vor dem Android 4.4 (API 19) AsyncTask hatte die fach Felder:

private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(10);

In Android 4.4 (API 19) die oben genannten Felder dies geändert werden:

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(128);

Diese Änderung erhöht die Größe der Warteschlange 128 Artikel und reduziert die maximale Anzahl von Threads auf die Anzahl der CPU-Kerne * 2 + 1. Apps können immer noch die gleiche Anzahl von Aufgaben vor.

Andere Tipps

Dies ermöglicht die parallele Ausführung auf allen Android-Versionen mit API 4+ (Android 1.6 +):

@TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11
void startMyTask(AsyncTask asyncTask) {
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    else
        asyncTask.execute(params);
}

Dies ist eine Zusammenfassung der Arhimed der ausgezeichneten Antwort.

Bitte stellen Sie sicher, verwenden Sie API-Level 11 oder höher als Ihr Projekt Build-Ziel. In Eclipse ist, dass Project > Properties > Android > Project Build Target. Dies wird nicht brechen Abwärtskompatibilität API Spiegel zu senken. Mach dir keine Sorgen, werden Sie Lint Fehler erhalten, wenn Ihr aus Versehen die spätere Verwendung als minSdkVersion eingeführt Funktionen. Wenn Sie wirklich verwenden möchten später eingeführt Funktionen als minSdkVersion, können Sie diese Fehler mit Anmerkungen zu unterdrücken, aber in diesem Fall müssen Sie kümmern sich um die Kompatibilität nehmen selbst . Dies ist genau das, was in dem Code-Schnipsel geschah oben.

Herstellung @sulai Vorschlag allgemeinerer:

@TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11
public static <T> void executeAsyncTask(AsyncTask<T, ?, ?> asyncTask, T... params) {
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    else
        asyncTask.execute(params);
}   

Nur das neueste Update (UPDATE 4) in @Arhimed ist makellos Antwort in der sehr guten Zusammenfassung von @sulai enthalten:

void doTheTask(AsyncTask task) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // Android 4.4 (API 19) and above
        // Parallel AsyncTasks are possible, with the thread-pool size dependent on device
        // hardware
        task.execute(params);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // Android 3.0 to
        // Android 4.3
        // Parallel AsyncTasks are not possible unless using executeOnExecutor
        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    } else { // Below Android 3.0
        // Parallel AsyncTasks are possible, with fixed thread-pool size
        task.execute(params);
    }
}

Das Android-Entwickler Beispiel Laden Bitmaps verwendet effizient eine benutzerdefinierte AsyncTask (von jellybean kopiert), so dass Sie das executeOnExecutor können in apis als senken <11

http://developer.android.com/training/displaying-bitmaps/ index.html

Sie den Code herunterladen und gehen Sie zu util-Paket.

Es ist posible. Meine Android-Gerät Version ist 4.0.4 und android.os.Build.VERSION.SDK_INT 15

Ich habe 3 Spinner

Spinner c_fruit=(Spinner) findViewById(R.id.fruits);
Spinner c_vegetable=(Spinner) findViewById(R.id.vegetables);
Spinner c_beverage=(Spinner) findViewById(R.id.beverages);

Und ich habe auch eine Async-Tack-Klasse.

Hier ist mein Spinner Lade Code

RequestSend reqs_fruit = new RequestSend(this);
reqs_fruit.where="Get_fruit_List";
reqs_fruit.title="Loading fruit";
reqs_fruit.execute();

RequestSend reqs_vegetable = new RequestSend(this);
reqs_vegetable.where="Get_vegetable_List";
reqs_vegetable.title="Loading vegetable";
reqs_vegetable.execute();

RequestSend reqs_beverage = new RequestSend(this);
reqs_beverage.where="Get_beverage_List";
reqs_beverage.title="Loading beverage";
reqs_beverage.execute();

Das funktioniert perfekt. Einer nach dem anderen meine Spinnereien geladen. Ich habe nicht vom Benutzer executeOnExecutor.

Hier ist meine Async-Task-Klasse

public class RequestSend  extends AsyncTask<String, String, String > {

    private ProgressDialog dialog = null;
    public Spinner spin;
    public String where;
    public String title;
    Context con;
    Activity activity;      
    String[] items;

    public RequestSend(Context activityContext) {
        con = activityContext;
        dialog = new ProgressDialog(activityContext);
        this.activity = activityContext;
    }

    @Override
    protected void onPostExecute(String result) {
        try {
            ArrayAdapter<String> adapter = new ArrayAdapter<String> (activity, android.R.layout.simple_spinner_item, items);       
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            spin.setAdapter(adapter);
        } catch (NullPointerException e) {
            Toast.makeText(activity, "Can not load list. Check your connection", Toast.LENGTH_LONG).show();
            e.printStackTrace();
        } catch (Exception e)  {
            Toast.makeText(activity, "Can not load list. Check your connection", Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }
        super.onPostExecute(result);

        if (dialog != null)
            dialog.dismiss();   
    }

    protected void onPreExecute() {
        super.onPreExecute();
        dialog.setTitle(title);
        dialog.setMessage("Wait...");
        dialog.setCancelable(false); 
        dialog.show();
    }

    @Override
    protected String doInBackground(String... Strings) {
        try {
            Send_Request();
            } catch (NullPointerException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        return null;
    }

    public void Send_Request() throws JSONException {

        try {
            String DataSendingTo = "http://www.example.com/AppRequest/" + where;
            //HttpClient
            HttpClient httpClient = new DefaultHttpClient();
            //Post header
            HttpPost httpPost = new HttpPost(DataSendingTo);
            //Adding data
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);

            nameValuePairs.add(new BasicNameValuePair("authorized","001"));

            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
            // execute HTTP post request
            HttpResponse response = httpClient.execute(httpPost);

            BufferedReader reader;
            try {
                reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
                StringBuilder builder = new StringBuilder();
                String line = null;
                while ((line = reader.readLine()) != null) {
                    builder.append(line) ;
                }

                JSONTokener tokener = new JSONTokener(builder.toString());
                JSONArray finalResult = new JSONArray(tokener);
                items = new String[finalResult.length()]; 
                // looping through All details and store in public String array
                for(int i = 0; i < finalResult.length(); i++) {
                    JSONObject c = finalResult.getJSONObject(i);
                    items[i]=c.getString("data_name");
                }

            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Wenn Sie Aufgaben parallel ausführen wollen, müssen Sie die Methode executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "your task name") nach Android-Version 3.0 aufrufen; aber diese Methode ist nicht vorhanden, bevor Android 3.0 und 1.6 nach, weil sie parallel ausführen, indem Sie selbst, also ich vorschlagen, dass Sie Ihre eigene AsyncTask-Klasse im Projekt anpassen, throw Ausnahme in verschiedener Android-Version zu vermeiden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top