AsyncTask: ProgressDialog und sauberes OrientationChange Handling (Version mit externer Klasse)

  • Antworten:0
Gelöschter Account
  • Forum-Beiträge: 694

13.08.2012, 15:00:06 via Website

EDIT 1: Ich habe eine ID eingeführt die man beim Start des AsyncTask setzen kann und die mit dem Listener zum Abschluss des AsyncTask zurückgeliefert wird. So können in einer Activity mehrere AsyncTask gestartet werden deren Ergebnisse in der selben Methode verarbeitet werden können (analog onActivityResult).

Hier geht's los:Es kamen ein paar Fragen bzgl. externer, recyclebarer AsyncTask Klasse. In diesem Szenario wird ein Listener (OnAsyncTaskCompletedListener) verwendet um der Activity das Ende mitzuteilen. Dabei kann ein Objekt (zum Beispiel ein Cursor) übergeben werden. Ein paar Helper Methoden für den AsyncTask und die Activity regeln das alles.

1.) In res/values/styles.xml aufnehmen:

1<resources>
2 <style name="MyProgressDialog" parent="@android:style/Theme.Dialog">
3 <item name="android:background">@android:color/transparent</item>
4 <item name="android:backgroundDimEnabled">false</item>
5 <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
6 <item name="android:windowBackground">@android:color/transparent</item>
7 <item name="android:windowContentOverlay">@null</item>
8 <item name="android:windowFrame">@null</item>
9 <item name="android:windowIsFloating">true</item>
10 <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
11 <item name="android:windowTitleStyle">@null</item>
12 </style>
13</resources>

2.) Neue Klasse MyProgressDialog.java:

1public class MyProgressDialog extends Dialog {
2
3 public MyProgressDialog(final Context context) {
4 super(context, R.style.MyProgressDialog);
5 }
6
7 public static MyProgressDialog show(final Context context, final CharSequence title, final CharSequence message) {
8 return show(context, title, message, false);
9 }
10
11 public static MyProgressDialog show(final Context context, final CharSequence title, final CharSequence message, final boolean indeterminate) {
12 return show(context, title, message, indeterminate, false, null);
13 }
14
15 public static MyProgressDialog show(final Context context, final CharSequence title, final CharSequence message, final boolean indeterminate, final boolean cancelable) {
16 return show(context, title, message, indeterminate, cancelable, null);
17 }
18
19 public static MyProgressDialog show(final Context context, final CharSequence title, final CharSequence message, final boolean indeterminate, final boolean cancelable, final OnCancelListener onCancelListener) {
20 MyProgressDialog dialog = new MyProgressDialog(context);
21 dialog.setCancelable(cancelable);
22 dialog.setOnCancelListener(onCancelListener);
23 dialog.setTitle(title);
24
25 dialog.addContentView(new ProgressBar(context), new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
26 dialog.show();
27
28 return dialog;
29 }
30}

3.) Neue Klasse OnAsyncTaskCompletedListener.java:

1public interface OnAsyncTaskCompletedListener {
2
3 public abstract void onAsyncTaskCompleted(final int task_id, final Object task_result);
4}

4.) Der AsyncTask in separater Klasse. Die Activity kann sich jederzeit mit detach() abmelden (zum Beispiel im OrientationChange) und mit attach() wieder anmelden. Letztendlich wird mit diesen beiden Methoden nur der Context der Activity und des Listeners verwaltet. In diesem Beispiel verwende ich als langlaufenden Task die zentrale Instanz einer SQLite Datenbank (siehe separates Beispiel hier im Code Snippets Forum). Das kann aber alles mögliche sein (Netzwerk Kommunikation, etc.). Der Task liefert im konkreten Fall über den Listener einen Cursor zurück an die Activity. Aber auch das kann auf die eigenen Bedürfnisse angepasst werden:

1public class MyAsyncTask extends AsyncTask<Void, Void, Cursor> {
2
3 private Context context;
4 private MyProgressDialog dialog;
5 private int task_id;
6 private OnAsyncTaskCompletedListener listener;
7
8 public MyAsyncTask(final int task_id, final Context context, final OnAsyncTaskCompletedListener listener) {
9 super();
10
11 this.context = context;
12 this.task_id = task_id;
13 this.listener = listener;
14 }
15
16 // Activity meldet sich zurueck nach OrientationChange
17 public void attach(final Context context, final OnAsyncTaskCompletedListener listener) {
18 this.context = context;
19 this.listener = listener;
20
21 processCreateDialog();
22 }
23
24 // Activity meldet sich ab
25 public void detach() {
26 processDismissDialog();
27
28 if (context != null) {
29 context = null;
30 }
31
32 if (listener != null) {
33 listener = null;
34 }
35 }
36
37 @Override
38 protected Cursor doInBackground(final Void... voids) {
39 return MyApplication.getSqliteOpenHelper().fetchIrgendwelcheDaten();
40 }
41
42 @Override
43 protected void onPostExecute(final Cursor cursor) {
44 if (listener != null) {
45 listener.onAsyncTaskCompleted(task_id, cursor);
46 }
47
48 detach();
49 }
50
51 @Override
52 protected void onPreExecute() {
53 processCreateDialog();
54 }
55
56 private void processCreateDialog() {
57 if (context != null) {
58 dialog = MyProgressDialog.show(context, null, null, true, false);
59 }
60 }
61
62 private void processDismissDialog() {
63 if (dialog != null) {
64 try {
65 dialog.dismiss();
66 } catch (Exception exception) {
67 }
68
69 dialog = null;
70 }
71 }
72}

5.) Die Activity mit den relevanten Methoden und dem implementierten OnAsyncTaskCompletedListener. Dieser prüft nun auch welcher von evtl. mehreren AsyncTasks gerade Vollzug meldet:

1public class MyListActivity extends ListActivity implements OnAsyncTaskCompletedListener {
2
3 private SimpleCursorAdapter adapter;
4 private MyAsyncTask task;
5
6 // Task meldet das Ergebnis
7 @Override
8 public void onAsyncTaskCompleted(final int task_id, final Object task_result) {
9 if (task_id == 1) {
10 Cursor cursor = (Cursor) task_result;
11 if (cursor != null) {
12 startManagingCursor(cursor);
13 adapter = new SimpleCursorAdapter(this,
14 R.layout.myrowlayout,
15 cursor,
16 new String[] { "einespalte" },
17 new int[] { R.id.myrowlayout_einespalte } );
18 if (adapter != null) {
19 setListAdapter(adapter);
20 }
21 }
22
23 task = null;
24 }
25 }
26
27 @Override
28 public void onCreate(final Bundle bundle) {
29 // ...
30
31 task = (MyAsyncTask) getLastNonConfigurationInstance();
32 if (task != null) {
33 task.attach(this, this);
34 } else {
35 task = new MyAsyncTask(1, this, this);
36 task.execute();
37 }
38
39 // ...
40 }
41
42 @Override
43 public Object onRetainNonConfigurationInstance() {
44 if (task != null) {
45 task.detach();
46 }
47
48 return task;
49 }
50}

— geändert am 10.09.2012, 19:33:54

Lukas TrümperGelöschter Account

Antworten