Verständniss-Problem AsyncTask's

  • Antworten:4
  • Bentwortet
swa00
  • Forum-Beiträge: 3.704

19.08.2016, 21:44:34 via Website

Hallo liebe Gemeinde,

heute habe ich zwei Fragen an euch ... - bzgl AsyncTask

1)
In einer Klasse foo gibt es mehrere AsyncTasks, die gestartet werden
Die Klasse foo wird z.b. in der MainActivity benutzt

foo MyFoo = new foo();
foo.start();

In foo.start() werden die AsynTasks gestartet

new fooTask_1.execute();
new fooTask_2.execute();

Frage : Was passiert mit fooTask_1 und fooTask_2, wenn ich lediglich in der MainActivity
angebe :

MyFoo = null; (der brutale Weg)

Die Frage bezieht sich darauf , dass ich in fooTask_1 namlich eine Routine drin habe , die
sich definitv aufhängen kann, ergo kann ich NICHT mit einem fooTask_1.cancel() arbeiten, die wird nicht erkannt.
Gibt es vielleicht eine elegante Lösung ???
( zur Erklärung : der Standard "MediaExtractor" ist in foo_Task_1 drin , dieser hängt sich auf und kommt auch nicht mehr raus , wenn ein URL-Stream keine gültigen Daten hat - der bleibt im Nirwana)

.
.
Zweite Frage :

Ich habe vom Mediaplayer den onPrepareListener implementiert.
Dort möchte ich zwei Tasks hintereinander starten

FFMpegPlayer.setOnPreparedListener(new FFmpegMediaPlayer.OnPreparedListener()
{
@Override
public void onPrepared(FFmpegMediaPlayer mp)
{
mp.start();
new fooTask_1().execute();
new fooTask_2().execute();
}

Interessanterweise geht dass nicht, FooTask_1 wird gestartet , erreicht den Initiator,kommt aber nicht in doInBackground rein, weil fooTask_2 direkt danach aufgerufen wurde.
Beide Tasks sind völlig autark - keine gemeinsamen Variablen
Wo fooTask_1 hängt, kann ich NICHT nachvollziehen - auch kein onPostExecute()

Ich habe es jetzt gelöst, indem ich einen KombiTask gebaut habe , aber mich interessiert es , warum ich nicht direkt hintereinander zwei Tasks starten kann.

Ich Danke euch im Voraus

— geändert am 19.08.2016, 23:32:55

Liebe Grüße - Stefan
[ App - Entwicklung ]

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

20.08.2016, 09:07:21 via App

Hallo swa00!
Zu 1) kann ich dir jetzt garnicht sicher sagen,
theoretisch müsste der der Task trotzdem weiterlaufen.
Scheib doch mal einen Test indem du im inneren eine endlosschleife mit Log.d() machst.
Wenn noch ausgaben kommen nachdem der übergeorddnete Task disposed(null)
ist, dann läufts weter.

Aber ich habe (weiß nicht mehr wo/wie/warum..) schon schlechte erfahrungen mit geschachtelten Threads/AsyncTasks gemacht. Also so ganz ohne ist mit den Handling.

Zu 2)
Der Theorie nach müsste das gehen, wird der Code im Mainthread ausgeführt?
Woran machst du fest, dass es nicht geht?
Hast du schonmal versucht das ganze mit Logs auszustatten und den Debugger zu benutzen?

— geändert am 20.08.2016, 09:08:38

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
swa00
  • Forum-Beiträge: 3.704

21.08.2016, 09:24:18 via Website

Guten Morgen Pascal,

erst mal vielen Dank für Deine Antwort - leider komme ich erst morgen wieder dazu , mich intensiver damit
auseinander zu setzen , so dass ich nochmal ein TestProjekt aufbauen kann .
Ich wollte mich nur erst mal noch lebend melden:-)

Zu 2) - womit mache ich das fest : Na ja , wenn der doinBackground nicht kommt ? :-)
(Auch wenn mal ein einfaches Log.d drin ist) - Debugger : auch der kommt nicht rein ...
Der Code wird im Mainthread im Fragment aufgerufen .... Pure Click & Shoot

Liebe Grüße - Stefan
[ App - Entwicklung ]

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

21.08.2016, 09:50:07 via App

Ok kurz googeln bringt Licht ins dunkle:
Seit Api1 gibt es den AsyncTask. Damals konnte man aber mit execute über den ThreadPool nur ein AsyncTask starten und den nächsten erst, wenn der erste fertig ist.
Seit Api 4 ist das behoben, dafür muss man aber AsyncTask#executeOnExecutor benutzen.

http://stackoverflow.com/questions/4068984/running-multiple-asynctasks-at-the-same-time-not-possible

Am besten man baut sich so eine Async Utils klasse wie hier:
http://stackoverflow.com/questions/18357641/is-it-possible-to-run-multiple-asynctask-in-same-time

LG Pascal //It's not a bug, it's a feature. :) ;)

swa00

Antworten
swa00
  • Forum-Beiträge: 3.704

28.08.2016, 10:56:21 via Website

[SOLUTION]

Nachdem ich mich nun einige Tage sehr intensiv mit dem von mir geschilderten Problem auseinander gesetzt habe,
möchte ich natürlich der Community die erfolgreichen Ergebnisse nicht vorenthalten ..
An dieser Stelle auch nochmal ein Danke an Pascal, der dazu auch den entsprechenden "Schupser" gegeben hat .

1)
Es ist definitv richtig , dass AsyncTasks bis zu API Level HONEYCOMP nur nacheinander ausgeführt werden können
Dies wurde ab HONEYCOMP geändert, so dass auch mehrere AsynTasks parallel gestartet werden können

Der Aufruf ist auch unterschiedlich : (execute / executeOnExecutor)

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
task.execute();

Somit hat man die Möglichkeit, mehrere Tasks gleichzeitig anzuwerfen

new fooTask_1().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new fooTask_2().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

Man könnte auch mehrfach den Gleichen anwerfen (Der Sinn sei erst mal dahingestellt)

new fooTask_1().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new fooTask_1().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
new fooTask_1().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

.
.

2) Canceling

In den oberen Beispielen haben wir mehrere Tasks lediglich mit new gestartet.
Für die Unterscheidung ,welcher Task denn wirklich auch läuft oder/und ihn auch stoppen kann,
müsste man sich einem Array/Map bedienen, um diese durch (Map).task.cancel() zu beenden.

Dies erfordert allerdings eine VerwaltungsMimik.

Wenn man ein und den Gleichen hintereinander benötigt, so müsste man erst einmal auf das Ende des Laufenden warten ( wieder irgend einen TimerTask :-( ) der dann mit das OK gibt = lästig.

Um dies zu Umgehen machen wir uns die Parallelität zu Nutze :

Man kann z.B. eine übergeordnete Variable nehmen, die dem Task beim start übergeben wird
und wenn sie sich geändert hat, den Task selbst beendet.

private int myCurrentID = 0;
myCurrentID = 100;
new fooTask_1(myCurrentID).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

Und im Task

im Constructor
construktor (int id)
this.localID = id;
im Background
if ( this.localID != myCurrentID) {cancel(true);return (Whatever);}

.
Somit hat der zu beendete Task in Ruhe Zeit, sich selbst zu töten und der neue Benötigte läuft schon .

Erweiterter Hinweis:
Der Aufruf von Tasks innerhalb Tasks oder Listener geht NICHT. Hierzu bleibt nur die Broadcast-Mimik
oder eine neue Instanz einer Klasse, die die Tasks beinhaltet.

lg
Stefan

— geändert am 28.08.2016, 15:38:45

Liebe Grüße - Stefan
[ App - Entwicklung ]

Pascal P.

Antworten