By Jay Liang
Here is another thing in android that kept me scratching my head for a day before i finally figure out how to do it properly because of the lack of documentations and books for Android development at this time.
The android app that I am currently working on has a search feature which will fire a http request and shows the result in a list view. The search can be slow depending on the network speed so I wanted to put a loading dialog on the screen to indicate that the app is processing.
There's a ProgressDialog class in Android's SDK, so the idea is to just first build and show a progress dialog before the search starts, and then cancel the dialog on search completion:
ProgressDialog pd = ProgressDialog.show(this,
"Title",
"Message",
true, false);
makeHttpRequest();
pd.dismiss();
The above snippet will not work because the makeHttpRequest() method is being executed on the UI thread (Android has a similar threading model as Swing) therefore the dialog will not show on the screen until makeHttpRequest() returns.
That's understandable, so how about putting the method in a background thread like this:
final ProgressDialog pd = ProgressDialog.show(this,
"Title",
"Message",
true, false);
new Thread(new Runnable(){
public void run(){
makeHttpRequest();
pd.dimiss();
}
}).start();
This works as we would expect, the progress dialog is shown and then it will disappear when makeHttpRequest() is finished.
However, here's the difficult bit. The above code will cause your application to crash if the user change the phone's orientation while the progress dialog is not yet dismissed.
W/dalvikvm( 292): threadid=3: thread exiting with uncaught exception
(group=0x40010e28)
E/AndroidRuntime( 292): Uncaught handler: thread main exiting due to uncaught exception
E/AndroidRuntime( 292): java.lang.IllegalArgumentException: View not attached to window manager
E/AndroidRuntime( 292): at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java: 331)
E/AndroidRuntime( 292): at
android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:200)
E/AndroidRuntime( 292): at android.view.Window$LocalWindowManager.removeView(Window.java:401)
E/AndroidRuntime( 292): at
android.app.Dialog.dismissDialog(Dialog.java:249)
E/AndroidRuntime( 292): at android.app.Dialog.access$000(Dialog.java:59)
E/AndroidRuntime( 292): at android.app.Dialog$1.run(Dialog.java:93)
E/AndroidRuntime( 292): at
android.app.Dialog.dismiss(Dialog.java:233)
E/AndroidRuntime( 292): at android.app.Dialog.cancel(Dialog.java:838)
E/AndroidRuntime( 292): at com.yellowbook.android2.SearchHelper$3.handleMessage(SearchHelper.java:97)
E/AndroidRuntime( 292): at android.os.Handler.dispatchMessage(Handler.java:88)
E/AndroidRuntime( 292): at android.os.Looper.loop(Looper.java:
123)
E/AndroidRuntime( 292): at android.app.ActivityThread.main(ActivityThread.java:3742)
E/AndroidRuntime( 292): at
java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 292): at
java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime( 292): at com.android.internal.os.ZygoteInit
$MethodAndArgsCaller.run(ZygoteInit.java:739)
E/AndroidRuntime( 292): at
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
E/AndroidRuntime( 292): at
dalvik.system.NativeStart.main(Native Method)
That is because by default, activities in Android will be destroyed and recreated on orientation change. Since the progress dialog is no longer 'attached' to the view after the activity is re-created, it blows up once the activity was destroyed. The problem has to do with the internal UI managements of android which i won't attempt to explain here.
Long story short, I figured out a working solution to the above problem. Rather than creating and showing the d