Bis zum 15.2.2012 habe ich noch keine gute Erklärung und keinen Grund gefunden, warum dies nicht funktioniert. Am nächsten an einer Lösung ist die Verwendung des traditionellen Thread- Ansatzes. Warum sollte dann eine Klasse in das Android SDK aufgenommen werden, die (anscheinend) nicht funktioniert?
Evenin 'SO!
Ich habe eine AsyncTask-Unterklasse:
// ParseListener had a callback which was called when an item was parsed in a
// RSS-xml, but as stated further down it is not used at all right now.
private class xmlAsync extends AsyncTask<String, RSSItem, Void> implements ParseListener
Das wird so ausgeführt:
xmlAsync xmlThread = new xmlAsync();
xmlThread.execute("http://www.nothing.com");
Jetzt ist diese Unterklasse auf einen kleinen Fehler gestoßen. Früher wurde XML-Analyse durchgeführt, aber als ich bemerkte, dass doInBackground () nicht aufgerufen wurde, habe ich es Zeile für Zeile entfernt und schließlich genau das erreicht:
@Override
protected Void doInBackground(String... params)
{
Log.v(TAG, "doInBackground");
return null;
}
Was aus irgendeinem Grund nichts protokollierte. Ich habe jedoch Folgendes hinzugefügt:
@Override
protected void onPreExecute()
{
Log.v(TAG, "onPreExecute");
super.onPreExecute();
}
Und diese Zeile wird tatsächlich beim Ausführen des Threads protokolliert. Also wird onPreExecute () irgendwie aufgerufen, aber nicht doInBackground () . Ich habe eine andere AsyncTask, die gleichzeitig im Hintergrund läuft, was gut funktioniert.
Ich verwende die App derzeit auf einem Emulator, SDK Version 15, Eclipse, Mac OS X 10.7.2, in der Nähe des Nordpols.
BEARBEITEN:
@Override
protected void onProgressUpdate(RSSItem... values) {
if(values[0] == null)
{
// activity function which merely creates a dialog
showInputError();
}
else
{
Log.v(TAG, "adding "+values[0].toString());
_tableManager.addRSSItem(values[0]);
}
super.onProgressUpdate(values);
}
_tableManager.addRSSItem () fügt einer SQLiteDatabase mehr oder weniger eine Zeile hinzu, die mit dem Kontext der Aktivität initialisiert wird. PublishProgress () wird vom Rückruf des Interface ParseListener aufgerufen. Da ich jedoch in doInBackground () nur log.v mache, fand ich dies zunächst unnötig, um es überhaupt aufzurufen.
EDIT 2:
Okay, um ganz klar zu sein, dies ist die andere AsyncTask, die in derselben Aktivität ausgeführt wird und einwandfrei funktioniert.
private class dbAsync extends AsyncTask<Void, RSSItem, Void>
{
Integer prevCount;
boolean run;
@Override
protected void onPreExecute() {
run = true;
super.onPreExecute();
}
@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
run = true;
prevCount = 0;
while(run)
{
ArrayList<RSSItem> items = _tableManager.getAllItems();
if(items != null)
{
if(items.size() > prevCount)
{
Log.v("db Thread", "Found new item(s)!");
prevCount = items.size();
RSSItem[] itemsArray = new RSSItem[items.size()];
publishProgress(items.toArray(itemsArray));
}
}
SystemClock.sleep(5000);
}
return null;
}
@Override
protected void onProgressUpdate(RSSItem... values) {
ArrayList<RSSItem> list = new ArrayList<RSSItem>();
for(int i = 0; i < values.length; i++)
{
list.add(i, values[i]);
}
setItemsAndUpdateList(list);
super.onProgressUpdate(values);
}
@Override
protected void onCancelled() {
run = false;
super.onCancelled();
}
}
EDIT 3:
Seufz, tut mir leid, dass ich schlecht darin bin, Fragen zu stellen. Aber hier ist die Initialisierung der Aufgaben.
xmlAsync _xmlParseThread;
dbAsync _dbLookup;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_dbLookup = new dbAsync();
_dbLookup.execute();
_xmlParseThread = new xmlAsync();
_xmlParseThread.execute("http://www.nothing.com", null);
}
Antworten:
Matthieus Lösung wird für die meisten gut funktionieren, aber einige können Probleme haben; es sei denn, Sie graben in viele Links, die hier oder im Internet bereitgestellt werden, wie Anders Göransson Erklärung. Ich versuche hier einige andere Lesevorgänge zusammenzufassen und die Lösung schnell zu erklären, wenn executeOnExecutor immer noch in einem einzelnen Thread arbeitet ...
Das Verhalten von
AsyncTask().execute();
hat sich durch Android-Versionen geändert. Bevor Donut- Aufgaben (Android: 1.6 API: 4) seriell ausgeführt wurden, wurden Aufgaben von Donut bis Gingerbread (Android: 2.3 API: 9) parallel ausgeführt. da die Ausführung von Honeycomb (Android: 3.0 API: 11) wieder auf sequentiell umgestellt wurde;AsyncTask().executeOnExecutor(Executor)
Für die parallele Ausführung wurde jedoch eine neue Methode hinzugefügt.Bei der sequentiellen Verarbeitung werden alle Async-Aufgaben in einem einzigen Thread ausgeführt und müssen daher warten, bis die vorherige Aufgabe endet. Wenn Sie Code sofort ausführen müssen, müssen Aufgaben in separaten Threads parallel verarbeitet werden.
Mit AsyncTask ist die serielle Ausführung zwischen Donut- und Honeycomb-Versionen nicht verfügbar, während die parallele Ausführung vor Donut nicht verfügbar ist.
Für die parallele Verarbeitung nach Donut: Überprüfen Sie die Build-Version und verwenden Sie basierend darauf die Methoden .execute () oder .executeOnExecutor (). Der folgende Code kann helfen ...
NOTE:
Die Funktion.executeOnExecutor()
prüft, ob dastargetSdkVersion
Projekt kleiner oder gleichHONEYCOMB_MR1
(Android: 2.1 API: 7) ist, und erzwingt dann, dass der Executor dies istTHREAD_POOL_EXECUTOR
(wodurch Aufgaben nacheinander in Honeycomb ausgeführt werden).Wenn Sie noch keinen definiert haben ,
targetSdkVersion
dannminSdkVersion
wird automatisch als das betrachtettargetSdkVersion
.Wenn Sie Ihre AsyncTask parallel auf Post Honeycomb ausführen, können Sie sie daher nicht
targetSdkVersion
leer lassen.quelle
Sie sollten diese Antwort überprüfen : https://stackoverflow.com/a/10406894/347565 und den darin enthaltenen Link zu Google-Gruppen.
Ich hatte ein ähnliches Problem wie Sie, immer noch unklar, warum es nicht funktioniert, aber ich habe meinen Code so geändert und das Problem ist weg:
quelle
Sie können dies auf zwei Arten tun:
Weg 1 :
Falls Weg 1 für Sie nicht funktioniert, versuchen Sie Weg 2 .
Weg 2 :
Hoffe das wird dir helfen.
quelle
Ich hatte das gleiche Problem: Ich kann keine zweite AsyncTask ausführen, nachdem ich bei einem ersten "execute" aufgerufen habe: doInBackground wird nur für die erste aufgerufen.
Um zu beantworten, warum dies passiert, überprüfen Sie diese Antwort (unterschiedliches Verhalten je nach SDK)
In Ihrem Fall kann dieses Hindernis jedoch mit executeOnExecutor (verfügbar ab 3.0, das mit 4.0.3 für mich funktioniert hat) vermieden werden. Beachten Sie jedoch die Einschränkungen hinsichtlich der Größe des Thread-Pools und der Warteschlange.
Können Sie so etwas versuchen:
Für Ihre Update-Frage: Sie wird in den Dokumenten erläutert. Grundsätzlich nur, um alle Probleme zu vermeiden, die durch Multithreading wie Interferenzen entstehen können.
quelle
Eine Sache, die ich gerne wissen würde und die Ihr Problem möglicherweise tatsächlich beheben könnte, ist, wo Sie die Instanz Ihrer Klasse instanziieren und die Methode execute () aufrufen. Wenn Sie die Dokumentation zu AsyncTask lesen, müssen beide Vorgänge im Haupt-UI-Thread ausgeführt werden. Wenn Sie Ihr Objekt erstellen und execute von einem anderen Thread aus aufrufen, wird möglicherweise onPreExecute ausgelöst. Ich bin mir hier nicht 100% sicher, aber der Hintergrund-Thread wird nicht erstellt und ausgeführt.
Wenn Sie die Instanz Ihrer AsyncTask aus einem Hintergrundthread oder einer anderen Operation erstellen, die nicht im Haupt-UI-Thread ausgeführt wird, können Sie die folgende Methode verwenden: Activity.runOnUiThread (Runnable)
Sie benötigen Zugriff auf eine Instanz Ihrer ausgeführten Aktivität, um diese Methode aufzurufen. Sie können jedoch Code auf dem UI-Thread von einem anderen Code ausführen, der nicht auf dem UI-Thread ausgeführt wird.
Hoffe das macht Sinn. Lassen Sie mich wissen, ob ich mehr helfen kann.
David
quelle
Android ist brutal! Ich kann das nicht glauben, welche Flakey-Implementierung sich von Tag zu Tag ändert. An einem Tag ist es ein einzelner Thread, am nächsten 5 ist der andere 128.
Wie auch immer, hier ist ein fast geringerer Ersatz für die serienmäßige AsyncTask. Sie können es sogar AsyncTask nennen, wenn Sie möchten, aber um Verwirrung zu vermeiden, heißt es ThreadedAsyncTask. Sie müssen executeStart () anstelle von execute aufrufen, da execute () final ist.
quelle
Ich weiß, dass dies für den Thread sehr spät sein kann, aber es gibt einen Grund, warum es bei späteren Android-Emulatoren nicht funktioniert. Als asynctask eingeführt wurde, ließ Android Sie immer nur eine nach der anderen ausführen. Einige Zeit später, da ich nicht sicher bin, welche Version es Ihnen ermöglichte, mehrere Asynctasks gleichzeitig auszuführen, verursachte dies Probleme in vielen Apps, und so wurden sie in Honeycomb + nur wieder verwendet Zulassen, dass jeweils eine Asynctask ausgeführt wird. Es sei denn, Sie ändern den Thread-Pool manuell. Hoffe, das klärt ein oder zwei Dinge für die Menschen.
quelle
Ich denke, es ist der SDK. ich hatte das gleiche problem und nachdem ich target sdk von 15 auf 11 geändert hatte, funktioniert alles perfekt.
Mit sdk15 wird doInBackground niemals aufgerufen, obwohl AsyncTask.Status ausgeführt wird. Ich denke, es hat etwas mit dem UI-Thread zu tun.
quelle
Basierend auf Matthieus Antwort finden Sie unten eine Hilfsklasse , um Ihre
AsyncTask
abhängig von der SDK-Version korrekt auszuführen, um zu vermeiden, dass Code in Ihrer Anwendung dupliziert wird:Anwendungsbeispiel:
...
quelle