[ERLEDIGT] Tipps für AsyncTask Klasse

lordzwieback

lordzwieback

Erfahrenes Mitglied
210
Moin,

ich habe in einem meiner Projekte mehrere AsyncTasks und würde diese gerne in eine eigene Klasse auslagern. Habe mich mal durch einige Beispiele gesucht. Da ist immer nur ein AsyncTask als eigene Klasse angegeben. Ist es auch möglich, mehrere Tasks in eine Klasse zu packen und die Tasks dann aus der Klasse raus zu starten?
 
Beziehungsweise wie stelle ich es an, dass ich dann von der AsyncTask Klasse in Pre und PostExecute auf die jeweils gerade aktive Activity und dessen UI zugreifen kann?
 
Spontan fallen mir unter anderem folgende Lösungen ein (Pseudocode, gerade zu wenig Zeit um die Syntax korrekt zu testen):

Code:
class AsyncTasks {
  public static AsyncTask TASK1 = new AsyncTask() { ...}
  public static AsyncTask TASK2 = new AsyncTask() { ...}
  public static AsyncTask TASK2 = new AsyncTask() { ...}
}

AsyncTasks.TASK1.execute(...)
AsyncTasks als anonyme Klassen in statischen Feldern.

Code:
public class AsyncTasks extends AsyncTask {
  ...
  doInBackground(String type, String ... args) {
    switch (type) {
      case "Task1": execute1();break;
      case "Task2": execute2();break;
      case "Task3": execute3();break;
    }
  }
  ...
  execute1() {...}
  execute2() {...}
  execute2() {...}
}

Ein Task, der über einen Typ Parameter entscheidet was zu tun ist.


Code:
public abstract class CustomAsyncTask extends AsyncTask {
 
  abstract doInternal();
 
  ...
  doInBackground() {
    [common code]
    doInternal();
  }
  ...
}

private class Task1 extends CustomAsyncTask {
  doInteral() {...}
}

Oberklasse mit gemeinsamen Code und Unterklassen die nur eine Methode überschreiben müssen.


Das sind auch alles Lösungen die mehr oder weniger an Design Patterns angelehnt sind. Welche das genau sind müsste ich jetzt nachschauen :)

Wenn du noch mehr Lösungen willst, kann ich auch gerne nochmal drüber nachdenken.

edit: deinen zweiten Post hab ich beim Schreiben noch nicht gesehen.
 
  • Danke
Reaktionen: lordzwieback und swa00
a) da machste eine Klasse a la "MeineTaskSammelung"
b) darein haust dir alle Tasks MyTaskA, MyTaskB mit constructor

und dann kannste sowas hier machen

MeineTaskSammelung MTS = new MeineTaskSammelung(mActivity);

new MTS.MyTaskA(mActivity)..

Welchen Zweck das allerdings haben soll, entzieht sich meinem Vorstellungsvermögen :)
Mach lieber brav eigene Java Files

Kostet doch nur Strom und erhöht die Übersichtlichkeit :)
 
  • Danke
Reaktionen: lordzwieback
Bezüglich deiner follow-Up Frage:

Ich habe inzwischen eigentlich in fast allen meinen Apps folgendes Pattern angewendet:

- eigene Application Klasse mit einer statischen get() Methode damit ich grundsätzlich von überall dran komme. (in onCreate wird die Instanz auf ein statisches Feld gesetzt)
- Gemeinsame abstrakte BaseActivity Klasse
-- in onResume ruft diese auf: App.get().setForegroundActivity(this);
-- in onPause ruft diese auf App.get().removeForegroundActivity(this);

Das gleiche geht auch mit Fragmenten wenn man es genauer haben will.
Die App weiß also damit immer welche Activity und welches Fragment gerade im Vordergrund sind. Remove mit (this) removed auch nur wenn savedActivity == (this) ist, damit eine eventuell komische Aufrufreihenfolge nichts kaputt macht.

Die App hat dann noch eine getForegroundActivity Methode.
 
  • Danke
Reaktionen: lordzwieback und swa00
Erstmal danke für eure schnellen Antworten. Nur um das fix klarzustellen, mit...
swa00 schrieb:
Mach lieber brav eigene Java Files
... meinst du für jeden AsyncTask einfach ein eigenes JavaFile und gut ist?
 
Moritz , du weisst, dass jeder Code-Gestörte seine eigene Technik hat
Die von deek ist auch nicht von der Hand zu weisen. (hat was)

Ich mache mir in meinem Projekten immer ein neues Modul ( also einen quasi Folder "MYTASKS")
und darin würde ich für jeden Task ein eigenes File erstellen .

Für mich persönlich ist das übersichtlicher, wenn ich auf Bugsuche gehe.
(Ich hasse scrollen in einem Spaghetti-Code)
 
Zuletzt bearbeitet:
  • Danke
Reaktionen: deek
@deek Die Antwort auf meine Follow Up Frage werde ich mir mal genauer anschauen, klingt interessant. Aber das versuche ich dann erstmal in einer kleinen BeispielApp. :)
[doublepost=1495092640,1495092568][/doublepost]
swa00 schrieb:
(Ich hasse scrollen in einem Spaghetti-Code)
Genau deshalb versuche ich gerade, das Ganze in den nächsten Tagen ein wenig umzubauen, der Übersichtlichkeit zuliebe.
 
Die beiden ersten Varianten in meinem Beispiel würde ich nur machen, wenn die Tasks ähnlich gelagerter Aufgaben haben. Sonst wird es echt zu unübersichtlich in dem File. Wenn die komplett verschiedene Sachen machen bin ich auch bei einer Klasse und einem File pro Task wie swa00
 
Irgendwie komme ich mit dem "AsyncTask mit UI Schicht von Activity verbinden" nicht so ganz klar.. Folgendes habe ich zusammengebastelt:

AsyncTask:
Code:
public class AsyncFTPConnect  extends AsyncTask<String, Void, Boolean> {
    private static final String TAGFTPCONN = "_async_ftp_conn";
    FTPClient mFTPClient = new FTPClient();

    protected MainActivity context;
    private String host = "";
    private String username = "";
    private String password = "";

    // constructor method
    public AsyncFTPConnect(MainActivity c, String hst, String usr, String pwd) {
        this.context = c;
        this.host = hst;
        this.username = usr;
        this.password = pwd;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        context.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                context. ??????????????????????????????????????????
            }
        });
    }

    @Override
    protected Boolean doInBackground(String... strings) {
        try {
            //connection to host
            mFTPClient.connect(host, 21);
            // check the reply code. if positive -> connection is working
            if (FTPReply.isPositiveCompletion(mFTPClient.getReplyCode())) {
                // login using username and password
                boolean status = mFTPClient.login(username, password);
                Log.i(TAGFTPCONN, "Login Status: " + status);
                if (status) {
                    //define the correct transfer mode -> binary (for text, images, compressed files etc)
                    mFTPClient.enterLocalPassiveMode();
                    Log.i(TAGFTPCONN, "connected to host " + host);
                }
                return status;
            }

        } catch (Exception e) {
            Log.e(TAGFTPCONN, "Error: could not connect to host " + host + "\n" + e);
        }
        return false;
    }

    @Override
    protected void onPostExecute(Boolean result) {
        super.onPostExecute(result);
    }
}

MainActivity:
Code:
public class MainActivity extends AppCompatActivity {
    private TextView test;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        test = (TextView) findViewById(R.id.headerTaetigkeit);
        test.setText("Hallo");
        new AsyncFTPConnect(this, "xxxxx", "xxxxx", "xxxxxxxx").execute();
    }
}

Habe mir das alles so wie es jetzt steht aus einem kleinen Tutorial zusammengebastelt. Habe auf der MainActivity ein TextView initialisiert, on welchem ich testweise den setText ändern wollte (im Async). Im Async habe ich dann im Konstruktor meinen Context angegeben. Im Beispiel wird dann über die im Construktor zugewiesene context-Variable der TextView angesprochen. Aber irgendwie wird, wenn ich im "public void run()" (siehe onPreExecute()) context. angebe das TextView nicht als Objekt gefunden.

Hoffe, es ist verständlich, wo ich gerade hänge.. bin für die nächste Stunde weg, also nicht wundern, wenn ich nicht antworte. Danke schonmal :)
 
Übergib einfach deinem Constructor deines Task die Activity aus deiner MainActivity.

Code:
  // constructor method
    public AsyncFTPConnect(Activity c, String hst, String usr, String pwd) {
        this.mActivity = c;
        this.host = hst;
        this.username = usr;
        this.password = pwd;
    }


Code:
 @Override
    protected void onPreExecute() {
        super.onPreExecute();
        mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mActivity......
            }
        });
    }



ODER

Übergib doch einfach dem Constructor dein View und die Activity
 
Ich steh wohl wieder aufm Schlauch...
Ich hab dem Construktor meine Activity übergeben (siehe Code oben). Im Beispiel wird dann im public void run() direkt auf den TextView aus der MainActivity zugegriffen, das geht bei mir garnicht.

Etwa so:
Code:
@Override
    protected void onPreExecute() {
        super.onPreExecute();
        mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mActivity.meinTextView.setText("Hallo");
            }
        });
    }
Ich kann hier mein TextView von der MainActivity nicht einbinden bzw. es wird garnicht angezeigt.
 
Moritz , nochmal .
du übergibst ganz oben nicht die Activity , sondern die Instanz einer Klasse ( MainActivity)
(Siehe meine Änderung)

Des weiteren kannst du beim Aufruf des Tasks auch die Instanz deines TextViews mit übergeben.
Code:
 // constructor method
    public AsyncFTPConnect(Activity c, TextView tv,String hst, String usr, String pwd) {
        this.mActivity = c;
        this.tv = tv <-----------------
        this.host = hst;
        this.username = usr;
        this.password = pwd;
    }


und dann später

Code:
@Override
    protected void onPreExecute() {
        super.onPreExecute();
        mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run()
            {
                tv.setText("Hallo");   <---------------
            }
        });
    }
 
So, ich melde mich hier nochmal zu Wort. Habe mich dazu entschlossen, das mit den Asyncs erstmal hinten anzustellen und sie dort stehen zu lassen, wo sie momentan stehen, da noch andere (wichtigere) Sachen in dem Projekt erledigt werden müssen. Werde aber auf die Tipps aus dem Thread bei Bedarf wieder zurückgreifen, danke euch. :)
 
Entwickler auf der Flucht :)

Du kannst Deinen Chef bei Gelegenheit mal mitteilen , dass neben dem Coden auch die Zeit zum
Aufräumen, Optimieren und Dokumentieren gehört - sonst wird es später doppelt so teuer :)
 
Naaaa, nicht auf der Flucht. Habe aber noch Fehler gefunden, die ausgebessert werden müssen, bevor ich mich in den wohlverdienten Urlaub verziehe. Und da die Asyncs ja eigentlich problemlos funktionieren, mache ich mich erst ans Fehler beheben. :)
 

Ähnliche Themen

netfreak
  • netfreak
Antworten
10
Aufrufe
461
netfreak
netfreak
5
Antworten
0
Aufrufe
1.150
586920
5
Y
Antworten
4
Aufrufe
1.227
swa00
swa00
Zurück
Oben Unten