How to handle screen orientation change when progress dialog and background thread active?

"YOU AND THE ART OF ONLINE DATING" is the only product on the market that will take you step-by-step through the process of online dating, provide you with the resources to help ensure success. Get it now!

When you switch orientations, Android will create a new View. You're probably getting crashes because your background thread is trying to change the state on the old one. (It may also be having trouble because your background thread isn't on the UI thread) I'd suggest making that mHandler volatile and updating it when the orientation changes.

1 You might have pinpointed the reason for the crash. I got rid of the crash, but I still haven't figured out how to restore the UI to the state it was in before the orientation change in a reliable way. But your answer moved me forward, so awarding it as answer.

– Heikki Toivonen Jul 13 '09 at 4:35 1 You should get an onStart in your activity when the orientation changes. Essentially, you have to reconfigure the view using the old data. So I'd suggest requesting numerical status udpates from the progress bar and rebuilding a new view when you get that new 'onStart' I can't remember offhand if you get a new activity as well but some hunting through the documentation should help.

– haseman Jul 13 '09 at 18:31 Having played with it recently, I can pass on that you do get a new activity when your app changes orientation. (You also get a new view) If you try to update the old view you'll get an exception because the old view has an invalid application context (your old activity) You can kinda get around this by passing in myActivity. GetApplicationContext() instead of a pointer to the activity itself.

– haseman Jul 30 '09 at 21:35.

You have to add this to the activity declaration in the manifest: android:configChanges="orientation" so it looks like The matter is that the system destroys the activity when a change in the configuration occurs. See ConfigurationChanges. So putting that in the configuration file avoids the system to destroy your activity.

Instead it invokes the onConfigurationChanged(Configuration) method.

– Janusz Apr 12 '10 at 8:34 11 This is definitely the best solution; as it simply rotates the layout (the behavior you expect in first place). Just be sure to put android:configChanges="orientation|keyboarddden" (because of phones that have landscape keyboard) – kape123 Oct 13 '10 at 20:41 10 This seems to be the behaviour I expect. However, the documentation indicates that the activity is destroyed "because any application resource, including layout files, can change based on any configuration value.

Thus the only safe way to handle a configuration change is to re-retrieve all resources". And besides orientation, there are many more reasons for the configuration to change: keyboarddden (I have edited the wiki answer already), uiMode (For example, going in or out of car mode ; night mode changing), etc.I now wonder wether this is actually a good answer. – rds Mar 10 at 16:49 @rds: I agree, there are other ways the configuration can change but this answer does cover what seems to be the common case.

– Matt May 22 at 18:11 4 This is not an acceptable solution.It just masks the true issue. – DDoSAttack Oct 13 at 0:55.

I came up with a rock-solid solution to these issues that conforms with the 'Android Way' of things. I have all my long-running operations using the IntentService pattern. That is my activities broadcast intents, the IntentService does the work, saves the data in the DB and then broadcasts STICKY intents.

The sticky part is important, such that even if the Activity was paused during during the time after the user initiated the work and misses the real time broadcast from the ItentService we can still respond and pick up the data from the calling Activity. ProgressDialogs can work into this pattern quite nicely with onSaveInstanceSate(). Basically, you need to save a flag that you have a progress dialog running in the saved instance bundle.DO NOT save the progress dialog object because this will leak the entire Activity.

To have a persistent handle to the progress dialog, I store it as a WeakReference in the application object. On orientation change or any thing else that causes the Activity to pause (phone call, user hits home etc) and then resume, I dismiss the old dialog and recreate a new dialog in the newly created Activity. For indefinite progress dialogs this is easy.

For progress bar style, you have to put the last known progress in the bundle and whatever information you're using locally in the activity to keep track of the progress. On restore the progress, you'll use this information to respawn the progress bar in the same state as before and then update based on the current state of things.So to summarize, putting long-running tasks into an IntentService coupled with juidcious use of onSaveInstanceState() allows you to efficiently keep track of dialogs and restore then across the Activity lifecycle events. Relevant bits of Activity code are below.

You'll also need logic in your BroadcastReceiver to handle Sticky intents appropriately, but that is beyond the scope of this. Public void doSignIn(View view) { waiting=true; AppClass app=(AppClass) getApplication(); String logingon=getString(R.string. Signon); app.

Dialog=new WeakReference(ProgressDialog. Show(AddAccount. This, "", logingon, true)); ..} @Override protected void onSaveInstanceState(Bundle saveState) { super.

OnSaveInstanceState(saveState); saveState. PutBoolean("waiting",waiting); } @Override public void onCreate(Bundle savedInstanceState) { super. OnCreate(savedInstanceState); if(savedInstanceState!

=null) { restoreProgress(savedInstanceState); } ...} private void restoreProgress(Bundle savedInstanceState) { waiting=savedInstanceState. GetBoolean("waiting"); if (waiting) { AppClass app=(AppClass) getApplication(); ProgressDialog refresher=(ProgressDialog) app.Dialog.get(); refresher.dismiss(); String logingon=getString(R.string. Signon); app.

Dialog=new WeakReference(ProgressDialog. Show(AddAccount. This, "", logingon, true)); } }.

I eventually followed this path, and it works best. – rds Jul 20 at 14:14.

I met the same problem. My activity needs to parse some data from a URL and it's slow. So I create a thread to do so then show a progressdialog.

I let the thread post a msg back to UI thread via Handler when it's finished. In Handler. HandleMessage, I get the data object (ready now) from thread and populate it to UI.So it's very similar to your example.

After many trial and error it looks like I found a solution. At least now I can rotate screen at any moment, before or after the thread is done.In all tests, the dialog is properly closed and all behaviors are as expected. What I did is shown below.

The goal is to fill my data model (mDataObject) and then populate it to UI. Should allow screen rotation at any moment without surprise. Class MyActivity { private MyDataObject mDataObject = null; private static MyThread mParserThread = null; // static, or make it singleton OnCreate() { ... Object retained = this.

GetLastNonConfigurationInstance(); if(retained! = null) { // data is already completely obtained before config change // by my previous self. // no need to create thread or show dialog at all mDataObject = (MyDataObject) retained; populateUI(); } else if(mParserThread!

= null && mParserThread.isAlive()){ // note: mParserThread is a static member or singleton object. // config changed during parsing in previous instance. Swap handler // then wait for it to finish.

MParserThread. SetHandler(new MyHandler()); } else { // no data and no thread. Likely initial run // create thread, show dialog mParserThread = new MyThread(..., new MyHandler()); mParserThread.start(); showDialog(DIALOG_PROGRESS); } } // http://android-developers.blogspot.com/2009/02/faster-screen-orientation-change.html public Object onRetainNonConfigurationInstance() { // my future self can get this without re-downloading // if it's already ready.

Return mDataObject; } // use Activity. ShowDialog instead of ProgressDialog. Show // so the dialog can be automatically managed across config change @Override protected Dialog onCreateDialog(int id) { // show progress dialog here } // inner class of MyActivity private class MyHandler extends Handler { public void handleMessage(msg) { mDataObject = mParserThread.getDataObject(); populateUI(); dismissDialog(DIALOG_PROGRESS); } } } class MyThread extends Thread { Handler mHandler; MyDataObject mDataObject; public MyHandler(..., Handler h) {...; mHandler = h;} // constructor with handler param public void setHandler(Handler h) { mHandler = h; } // for handler swapping after config change public MyDataObject getDataObject() { return mDataObject; } // return data object (completed) to caller public void run() { mDataObject = new MyDataObject(); // do the lengthy task to fill mDataObject with data lengthyTask(mDataObject); // done.

Notify activity mHandler. SendEmptyMessage(0); // tell activity: i'm ready. Come pick up the data.

} } That's what works for me. I don't know if this is the "correct" method as designed by Android -- they claim this "destroy/recreate activity during screen rotation" actually makes things easier, so I guess it shouldn't be too tricky. Let me know if you see a problem in my code.

As said above I don't really know if there is any side effect.

1 Thanks a lot! The hint to onRetainNonConfigurationInstance() and getLastNonConfigurationInstance() helped me to solve my problem. Thumbs up!

– sven Oct 28 '10 at 13:42 I think it is an over-complicated solution. – rds Mar 10 at 16:34.

I faced this same problem, and I came up with a solution that didn't invole using the ProgressDialog and I get faster results. What I did was create a layout that has a ProgressBar in it. Then in the onCreate method do the following public void onCreate(Bundle icicle) { super.

OnCreate(icicle); setContentView(R.layout. Progress); } Then do the long task in a thread, and when that's finished have a Runnable set the content view to the real layout you want to use for this activity. For example: mHandler.

Post(new Runnable(){ public void run() { setContentView(R.layout. My_layout); } }); This is what I did, and I've found that it runs faster than showing the ProgressDialog and it's less intrusive and has a better look in my opinion. However, if you're wanting to use the ProgressDialog, then this answer isn't for you.

This solution is elegant in a simple use case, but has drawbacks. You need to rebuild the full content view. SetContentView(R.layout.

My_layout); is not sufficient; you need to set all listeners, reset data, etc. – rds Mar 10 at 23:40 @rds you are right. This is really only a solution to a simple case, or if you need to do some heavy lifting in your onCreate method before displaying your view. – Pzanno Mar 11 at 19:12.

All, Got a really great explanation and possible solutions to this problem. Go through blog.doityourselfandroid.com/2010/11/14/... Lemme know if this helped.

This is exactly the problem that I was running into! Thanks for the link. – David Jul 25 at 5:27 You're welcome David.

Glad it helped. – arcamax Sep 15 at 7:57.

I discovered a solution to this that I haven't yet seen elsewhere. You can use a custom application object that knows if you have background tasks going, instead of trying to do this in the activity that gets destroyed and recreated on orientation change. I blogged about this in here.

Creating a custom Application is normally used to maintain a global application state. I don't say it doesn't work it, but it seems over-complicated. From the doc "There is normally no need to subclass Application.".

I largely prefer sonxurxo's answer. – rds Mar 10 at 16:41.

If you create a background Service that does all the heavy lifting (tcp requests/response, unmarshalling), the View and Activity can be destroyed and re-created without leaking window or losing data. This allows the Android recommended behavior, which is to destroy an Activity on each configuration change (eg. For each orientation change).

It is a bit more complex, but it is the best way for invoking server request, data pre/post-processing, etc. You may even use your Service to queue each request to a server, so it makes it easy and efficient to handle those things. The dev guide has a full chapter on Services.

A Service is more work than an AsyncTask but can be a better approach in some situations. It is not necessarily better, is it? That being said, I don't understand how this solves the problem of the ProgressDialog that is leaked from the main Activity.

Where do you instanciate the ProgressDialog? Where do you dismiss it? – rds Mar 10 at 18:12.

The original perceived problem was that the code would not survive a screen orientation change. Apparently this was "solved" by having the program handle the screen orientation change itself, instead of letting the UI framework do it (via calling onDestroy)). I would submit that if the underlying problem is that the program will not survive onDestroy(), then the accepted solution is just a workaround that leaves the program with serious other problems and vulnerabilities.

Remember that the Android framework specifically states that your activity is at risk for being destroyed almost at any time due to circumstances outside your control. Therefore, your activity must be able to survive onDestroy() and subsequent onCreate() for any reason, not just a screen orientation change. If you are going to accept handling screen orientation changes yourself to solve the OP's problem, you need to verify that other causes of onDestroy() do not result in the same error.

Are you able to do this? If not, I would question whether the "accepted" answer is really a very good one.

I going to contribute my approach to handling this rotation issue. This may not be relevant to OP as he's not using AsyncTask, but maybe others will find it useful. It's pretty simple but it seems to do the job for me: I have a login activity with a nested AsyncTask class called BackgroundLoginTask.In my BackgroundLoginTask I don't do anything out of the ordinary except to add a null check upon calling ProgressDialog's dismiss: @Override protected void onPostExecute(Boolean result) { if (pleaseWaitDialog!

= null) pleaseWaitDialog.dismiss(); ... } This is to handle the case where the background task finishes while the activity is not visible and, therefore, the progress dialog has already been dismissed by the onPause() method. Next, in my parent activity class, I create global static handles to my AsyncTask class and my ProgressDialog (the AsyncTask, being nested, can access these variables): private static BackgroundLoginTask backgroundLoginTask; private static ProgressDialog pleaseWaitDialog; This serves two purposes: First, it allows my Activity to always access the AsyncTask object even from a new, post-rotated activity. Second, it allows my BackgroundLoginTask to access and dismiss the ProgressDialog even after a rotate.

Next, I add this to onPause(), causing the progress dialog to disappear when our activity is leaving the foreground (preventing that ugly "force close" crash): if (pleaseWaitDialog! = null) pleaseWaitDialog.dismiss(); Finally, I have the following in my onResume method: if ((backgroundLoginTask! = null) && (backgroundLoginTask.getStatus() == Status.

RUNNING)) { if (pleaseWaitDialog! = null) pleaseWaitDialog.show(); } This allows the dialog to reappear after the activity is recreated. Here is the entire class: public class NSFkioskLoginActivity extends NSFkioskBaseActivity { private static BackgroundLoginTask backgroundLoginTask; private static ProgressDialog pleaseWaitDialog; private Controller cont; // This is the app entry point.

/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super. OnCreate(savedInstanceState); if (CredentialsAvailableAndValidated()) { //Go to main menu and don't run rest of onCreate method.

GotoMainMenu(); return; } setContentView(R.layout. Login); populateStoredCredentials(); } //Save current progress to options when app is leaving foreground @Override public void onPause() { super.onPause(); saveCredentialsToPreferences(false); //Get rid of progress dialog in the event of a screen rotation. Prevents a crash.

If (pleaseWaitDialog! = null) pleaseWaitDialog.dismiss(); } @Override public void onResume() { super.onResume(); if ((backgroundLoginTask! = null) && (backgroundLoginTask.getStatus() == Status.

RUNNING)) { if (pleaseWaitDialog! = null) pleaseWaitDialog.show(); } } /** * Go to main menu, finishing this activity */ private void gotoMainMenu() { startActivity(new Intent(getApplicationContext(), NSFkioskMainMenuActivity. Class)); finish(); } /** * * @param setValidatedBooleanTrue If set true, method will set CREDS_HAVE_BEEN_VALIDATED to true in addition to saving username/password.

*/ private void saveCredentialsToPreferences(boolean setValidatedBooleanTrue) { SharedPreferences settings = getSharedPreferences(APP_PREFERENCES, MODE_PRIVATE); SharedPreferences. Editor prefEditor = settings.edit(); EditText usernameText = (EditText) findViewById(R.id. EditTextUsername); EditText pswText = (EditText) findViewById(R.id.

EditTextPassword); prefEditor. PutString(USERNAME, usernameText.getText().toString()); prefEditor. PutString(PASSWORD, pswText.getText().toString()); if (setValidatedBooleanTrue) prefEditor.

PutBoolean(CREDS_HAVE_BEEN_VALIDATED, true); prefEditor.commit(); } /** * Checks if user is already signed in */ private boolean CredentialsAvailableAndValidated() { SharedPreferences settings = getSharedPreferences(APP_PREFERENCES, MODE_PRIVATE); if (settings. Contains(USERNAME) && settings. Contains(PASSWORD) && settings.

GetBoolean(CREDS_HAVE_BEEN_VALIDATED, false) == true) return true; else return false; } //Populate stored credentials, if any available private void populateStoredCredentials() { SharedPreferences settings = getSharedPreferences(APP_PREFERENCES, MODE_PRIVATE); settings. GetString(USERNAME, ""); EditText usernameText = (EditText) findViewById(R.id. EditTextUsername); usernameText.

SetText(settings. GetString(USERNAME, "")); EditText pswText = (EditText) findViewById(R.id. EditTextPassword); pswText.

SetText(settings. GetString(PASSWORD, "")); } /** * Validate credentials in a seperate thread, displaying a progress circle in the meantime * If successful, save credentials in preferences and proceed to main menu activity * If not, display an error message */ public void loginButtonClick(View view) { if (phoneIsOnline()) { EditText usernameText = (EditText) findViewById(R.id. EditTextUsername); EditText pswText = (EditText) findViewById(R.id.

EditTextPassword); //Call background task worker with username and password params backgroundLoginTask = new BackgroundLoginTask(); backgroundLoginTask. Execute(usernameText.getText().toString(), pswText.getText().toString()); } else { //Display toast informing of no internet access String notOnlineMessage = getResources(). GetString(R.string.

NoNetworkAccessAvailable); Toast toast = Toast. MakeText(getApplicationContext(), notOnlineMessage, Toast. LENGTH_SHORT); toast.show(); } } /** * * Takes two params: username and password * */ public class BackgroundLoginTask extends AsyncTask { private Exception e = null; @Override protected void onPreExecute() { cont = Controller.getInstance(); //Show progress dialog String pleaseWait = getResources().

GetString(R.string. PleaseWait); String commWithServer = getResources(). GetString(R.string.

CommunicatingWithServer); if (pleaseWaitDialog == null) pleaseWaitDialog= ProgressDialog. Show(NSFkioskLoginActivity. This, pleaseWait, commWithServer, true); } @Override protected Boolean doInBackground(Object... params) { try { //Returns true if credentials were valid.

False if not. Exception if server could not be reached. Return cont.

ValidateCredentials((String)params0, (String)params1); } catch (Exception e) { this. E=e; return false; } } /** * result is passed from doInBackground. Indicates whether credentials were validated.

*/ @Override protected void onPostExecute(Boolean result) { //de progress dialog and handle exceptions //Progress dialog may be null if rotation has been switched if (pleaseWaitDialog! = null) { pleaseWaitDialog.dismiss(); pleaseWaitDialog = null; } if (e! = null) { //Show toast with exception text String networkError = getResources().

GetString(R.string. ServerErrorException); Toast toast = Toast. MakeText(getApplicationContext(), networkError, Toast.

LENGTH_SHORT); toast.show(); } else { if (result == true) { saveCredentialsToPreferences(true); gotoMainMenu(); } else { String toastText = getResources(). GetString(R.string. InvalidCredentialsEntered); Toast toast = Toast.

MakeText(getApplicationContext(), toastText, Toast. LENGTH_SHORT); toast.show(); } } } } } I am by no means a seasoned Android developer, so feel free to comment.

Move the long task to a seperate class. Implement it as a subject-observer pattern. Whenever the activity is created register and while closing unregister with the task class.

Task class can use AsyncTask.

I don't see how that would help. Could you explain in more detail how this prevents the problems I am seeing. – Heikki Toivonen Jul 11 '09 at 17:14 1 As Haseman said it prevents the backend to access the UI elements and we can seperate the UI from backend, backend runs in seperate thread and it continues to run even after the screen is re-oriented and Register-UnRegister with the Backend task for status updates.

The real example I have solved using this is that I have a Download Task, I have moved that to a seperate thread, whenever the thread is created I register-unregister with it. – Vinay Jul 14 '09 at 17:17 Ok, I am revisiting this issue and I don't think I still fully understand this answer. Suppose we have the main activity start an AsyncTask to do a long-running network operation we don't want to interrupt during screen orientation change.

I don't see how the new activity can send a message to the AsyncTask started by the old activity. Can you give a code example? – Heikki Toivonen May 7 '10 at 7:54 @Heikki, is my implementation below what you mean?

– beetstra Apr 29 at 13:58.

I've tried EVERYTHING. Spent days experimenting. I didn't want to block the activity from rotating.My scenario was: A progress dialog showing dynamic information to the user.

E.g. : "Connecting to server...", "Downloading data...", etc.A thread doing the heavy stuff and updating the dialog Updating the UI with the results at the end. The problem was, when rotating the screen, every solution on the book failed.

Even with the AsyncTask class, which is the correct Android way of dealing with this situations. When rotating the screen, the current Context that the starting thread is working with, is gone, and that messes up with the dialog that is showing. The problem was always the Dialog, no matter how many tricks I added to the code (passing new contexts to running threads, retaining thread states through rotations, etc...).

The code complexity at the end was always huge and there was always something that could go wrong. The only solution that worked for me was the Activity/Dialog trick. It's simple and genius and it's all rotation proof: Instead of creating a Dialog and ask to show it, create an Activity that has been set in the manifest with android:theme="@android:style/Theme.

Dialog". So, it just looks like a dialog. Replace showDialog(DIALOG_ID) with startActivityForResult(yourActivityDialog, yourCode); Use onActivityResult in the calling Activity to get the results from the executing thread (even the errors) and update the UI.

On your 'ActivityDialog', use threads or AsyncTask to execute long tasks and onRetainNonConfigurationInstance to save "dialog" state when rotating the screen. This is fast and works fine. I still use dialogs for other tasks and the AsyncTask for something that doesn't require a constant dialog on screen.

But with this scenario, I always go for the Activity/Dialog pattern. And, I didn't try it, but it's even possible to block that Activity/Dialog from rotating, when the thread is running, speeding things up, while allowing the calling Activity to rotate.

Nice except that parameters must be passed through an Intent, which is more restrictive than the Object allowed by AsyncTask – rds Mar 29 at 21:24 @Rui I too used this method for the last year. It has now occurred to me though that this is also incorrect. Why would Google even have a Dialog if this was the way to 'fix' this issue?

The problem I see is that if you open ActivityB (Theme. Dialog) from ActivityA then ActivityA is moved down on the Activity stack thus is marked as ready to kill by the OS if necessary. Therefore, if you have a long running process and are showing some sort of faux progress 'dialog' and it took too long and memory ran low... ActivityA is killed and there is nothing to come back too upon progress complete.

– DDoSAttack Oct 13 at 0:47.

I have an implementation which allows the activity to be destroyed on a screen orientation change, but still destroys the dialog in the recreated activity successfully. I use ...NonConfigurationInstance to attach the background task to the recreated activity. The normal Android framework handles recreating the dialog itself, nothing is changed there.

I subclassed AsyncTask adding a field for the 'owning' activity, and a method to update this owner. Class MyBackgroundTask extends AsyncTask { MyBackgroundTask (Activity a, ...) { super(); this. OwnerActivity = a; } public void attach(Activity a) { ownerActivity = a; } protected void onPostExecute(Integer result) { super.

OnPostExecute(result); ownerActivity. DismissDialog(DIALOG_PROGRESS); } ... } In my activity class I added a field backgroundTask referring to the 'owned' backgroundtask, and I update this field using onRetainNonConfigurationInstance and getLastNonConfigurationInstance. Class MyActivity extends Activity { public void onCreate(Bundle savedInstanceState) { ... if (getLastNonConfigurationInstance()!

= null) { backgroundTask = (MyBackgroundTask) getLastNonConfigurationInstance(); backgroundTask. Attach(this); } } void startBackgroundTask() { backgroundTask = new MyBackgroundTask(this, ...); showDialog(DIALOG_PROGRESS); backgroundTask. Execute(...); } public Object onRetainNonConfigurationInstance() { if (backgroundTask!

= null && backgroundTask.getStatus()! = Status. FINISHED) return backgroundTask; return null; } ... } Suggestions for further improvement: Clear the backgroundTask reference in the activity after the task is finished to release any memory or other resources associated with it.

Clear the ownerActivity reference in the backgroundtask before the activity is destroyed in case it will not be recreated immediately. Create a BackgroundTask interface and/or collection to allow different types of tasks to run from the same owning activity.

If you maintain two layouts, all UI thread should be terminated. If you use AsynTask, then you can easily call .cancel() method inside onDestroy() method of current activity. @Override protected void onDestroy (){ removeDialog(DIALOG_LOGIN_ID); // remove loading dialog if (loginTask!

= null){ if (loginTask.getStatus()! = AsyncTask.Status. FINISHED) loginTask.

Cancel(true); //cancel AsyncTask } super.onDestroy(); } For AsyncTask, read more in "Cancelling a task" section at here. Update: Added condition to check status, as it can be only cancelled if it is in running state. Also note that the AsyncTask can only be executed one time.

Seems far too 'quick and dirty' to be true so please point out the flaws but what I found worked was... Within the onPostExecute method of my AsyncTask, I simply wrapped the '. Dismiss' for the progress dialog in a try/catch block (with an empty catch) and then simply ignored the exception that was raised. Seems wrong to do but appears there are no ill effects (at least for what I am doing subsequently which is to start another activity passing in the result of my long running query as an Extra).

– rds Mar 10 at 18:09 My progress dialog is a member variable of the activity class so I assumed that when the activity is destroyed and recreated it will be garbage collected and there is no leak. Am I wrong? – Simon Mar 28 at 20:01 Yes, I think it's wrong.

As you say, the Activity has a reference to the Dialog. When the configuration is changed, the first Activity is destroyed, which means all fields are set to null. But the low-level WindowManager also has a reference to the Dialog (since it is has not been dismissed yet).

The new Activity tries to create a new Dialog (in preExecute()) and the window manager raises a fatal exception preventing you from doing so. Indeed, if it does so, there would be no way to cleanly destroy the Dialog hence keeping a reference to the initial Activity.Am I right? – rds Mar 29 at 21:20.

The trick is to show/dismiss the dialog within AsyncTask during onPreExecute/onPostExecute as usual, though in case of orientation-change create/show a new instance of the dialog in the activity and pass its reference to the task. Public class MainActivity extends Activity { private Button mButton; private MyTask mTask = null; @Override public void onCreate(Bundle savedInstanceState) { super. OnCreate(savedInstanceState); setContentView(R.layout.

Main); MyTask task = (MyTask) getLastNonConfigurationInstance(); if(task! = null){ mTask = task; mTask. MContext = this; mTask.

MDialog = ProgressDialog. Show(this, "", "", true); } mButton = (Button) findViewById(R.id. Button1); mButton.

SetOnClickListener(new View.OnClickListener(){ public void onClick(View v){ mTask = new MyTask(MainActivity. This); mTask.execute(); } }); } @Override public Object onRetainNonConfigurationInstance() { String str = "null"; if(mTask! = null){ str = mTask.toString(); mTask.mDialog.dismiss(); } Toast.

MakeText(this, str, Toast. LENGTH_SHORT).show(); return mTask; } private class MyTask extends AsyncTask{ private ProgressDialog mDialog; private MainActivity mContext; public MyTask(MainActivity context){ super(); mContext = context; } protected void onPreExecute() { mDialog = ProgressDialog. Show(MainActivity.

This, "", "", true); } protected void onPostExecute(Void result) { mContext. MTask = null; mDialog.dismiss(); } @Override protected Void doInBackground(Void... params) { SystemClock. Sleep(5000); return null; } } }.

Tried to implement jfelectron's solution because it is a "rock-solid solution to these issues that conforms with the 'Android Way' of things" but it took some time to look up and put together all the elements mentioned. Ended up with this slightly different, and I think more elegant, solution posted here in it's entirety. Uses an IntentService fired from an activity to perform the long running task on a separate thread.

The service fires back sticky Broadcast Intents to the activity which update the dialog. The Activity uses showDialog(), onCreateDialog() and onPrepareDialog() to eliminate the need to have persistent data passed in the application object or the savedInstanceState bundle. This should work no matter how your application is interrupted.

Activity Class: public class TesterActivity extends Activity { private ProgressDialog mProgressDialog; private static final int PROGRESS_DIALOG = 0; @Override public void onCreate(Bundle savedInstanceState) { super. OnCreate(savedInstanceState); setContentView(R.layout. Main); Button be = (Button) this.

FindViewById(R.id. Test_button); b. SetOnClickListener(new OnClickListener() { public void onClick(View v) { buttonClick(); } }); } private void buttonClick(){ clearPriorBroadcast(); showDialog(PROGRESS_DIALOG); Intent svc = new Intent(this, MyService.

Class); startService(svc); } protected Dialog onCreateDialog(int id) { switch(id) { case PROGRESS_DIALOG: mProgressDialog = new ProgressDialog(TesterActivity. This); mProgressDialog. SetProgressStyle(ProgressDialog.

STYLE_HORIZONTAL); mProgressDialog. SetMax(MyService. MAX_COUNTER); mProgressDialog.

SetMessage("Processing..."); return mProgressDialog; default: return null; } } @Override protected void onPrepareDialog(int id, Dialog dialog) { switch(id) { case PROGRESS_DIALOG: // setup a broadcast receiver to receive update events from the long running process IntentFilter filter = new IntentFilter(); filter. AddAction(MyService. BG_PROCESS_INTENT); registerReceiver(new MyBroadcastReceiver(), filter); break; } } public class MyBroadcastReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { if (intent.

HasExtra(MyService. KEY_COUNTER)){ int count = intent. GetIntExtra(MyService.

KEY_COUNTER, 0); mProgressDialog. SetProgress(count); if (count >= MyService. MAX_COUNTER){ dismissDialog(PROGRESS_DIALOG); } } } } /* * Sticky broadcasts persist and any prior broadcast will trigger in the * broadcast receiver as soon as it is registered.

* To clear any prior broadcast this code sends a blank broadcast to clear * the last sticky broadcast. * This broadcast has no extras it will be ignored in the broadcast receiver * setup in onPrepareDialog() */ private void clearPriorBroadcast(){ Intent broadcastIntent = new Intent(); broadcastIntent. SetAction(MyService.

BG_PROCESS_INTENT); sendStickyBroadcast(broadcastIntent); }} IntentService Class: public class MyService extends IntentService { public static final String BG_PROCESS_INTENT = "com.mindspiker.Tester.MyService. TEST"; public static final String KEY_COUNTER = "counter"; public static final int MAX_COUNTER = 100; public MyService() { super(""); } @Override protected void onHandleIntent(Intent intent) { for (int I = 0; I Sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } Intent broadcastIntent = new Intent(); broadcastIntent. SetAction(BG_PROCESS_INTENT); broadcastIntent.

PutExtra(KEY_COUNTER, i); sendStickyBroadcast(broadcastIntent); } }} Manifest file entries: before application section: uses-permission android:name="com.mindspiker.Tester.MyService. TEST"/ uses-permission android:name="android.permission. BROADCAST_STICKY"/ inside application section service android:name=".MyService.

Screen orientation change is handled is successfully. But in the first case like stated before I get Kern Exec 3 at CAknViewAppUi::HandleResourceChangeL( aType );. Handle screen orientation change.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions