Asked  7 Months ago    Answers:  5   Viewed   28 times

I download some data from internet in background thread (I use AsyncTask) and display a progress dialog while downloading. Orientation changes, Activity is restarted and then my AsyncTask is completed - I want to dismiss the progess dialog and start a new Activity. But calling dismissDialog sometimes throws an exception (probably because the Activity was destroyed and new Activity hasn't been started yet).

What is the best way to handle this kind of problem (updating UI from background thread that works even if user changes orientation)? Did someone from Google provide some "official solution"?

 Answers

22

Step #1: Make your AsyncTask a static nested class, or an entirely separate class, just not an inner (non-static nested) class.

Step #2: Have the AsyncTask hold onto the Activity via a data member, set via the constructor and a setter.

Step #3: When creating the AsyncTask, supply the current Activity to the constructor.

Step #4: In onRetainNonConfigurationInstance(), return the AsyncTask, after detaching it from the original, now-going-away activity.

Step #5: In onCreate(), if getLastNonConfigurationInstance() is not null, cast it to your AsyncTask class and call your setter to associate your new activity with the task.

Step #6: Do not refer to the activity data member from doInBackground().

If you follow the above recipe, it will all work. onProgressUpdate() and onPostExecute() are suspended between the start of onRetainNonConfigurationInstance() and the end of the subsequent onCreate().

Here is a sample project demonstrating the technique.

Another approach is to ditch the AsyncTask and move your work into an IntentService. This is particularly useful if the work to be done may be long and should go on regardless of what the user does in terms of activities (e.g., downloading a large file). You can use an ordered broadcast Intent to either have the activity respond to the work being done (if it is still in the foreground) or raise a Notification to let the user know if the work has been done. Here is a blog post with more on this pattern.

Tuesday, June 1, 2021
 
jakubos
answered 7 Months ago
90

You need to check for a savedInstanceState [edit: in your parent activity], and if it exists, don't create your fragments.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    if (savedInstanceState == null) {
         // Do your oncreate stuff because there is no bundle   
    }
// Do stuff that needs to be done even if there is a saved instance, or do nothing
}
Friday, July 30, 2021
 
BlueNile
answered 5 Months ago
30

ToastNotificationHistoryChangedTrigger is fired whenever the collection of toast notification history from your app changes on the device. Subscribing this trigger, will allow your app to get notified when:

  • A toast notification is removed by the user from action center;
  • A toast notification is expired and removed by the system from action center;
  • A toast notification is delivered form your app, via push;

Note: the only thing your app wouldn’t be notified for, is a local toast being popped/added, since it is not necessary to notify your app client about something it just did.

So generally, an app can be notified with ToastNotificationHistoryChangedTrigger when the app’s collection of notifications is changed in any way that’s not caused by the app’s local client. If your application added the toast notification by itself, the trigger won't be fired.

Saturday, August 7, 2021
 
John Oleynik
answered 4 Months ago
76

Yeah, this is a common trap I'm falling in all the time myself. First of all let me say that your solution of calling DialogTest.udateListener() in onResume() seems to be fully appropriate to me.

An alternative way would be to use a ResultReceiver which can be serialized as a Parcelable:

public class DialogTest extends DialogFragment {

public static DialogTest newInstance(ResultReceiver receiver, int titleId, int messageId) {
    DialogTest frag = new DialogTest();
    Bundle args = new Bundle();
    args.putParcelable("receiver", receiver);
    args.putInt("titleId", titleId);
    args.putInt("messageId", messageId);
    frag.setArguments(args);
    return frag;
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    int titleId = getArguments().getInt("titleId");
    int messageId = getArguments().getInt("messageId");
    ResultReceiver receiver = getArguments().getParcelable("receiver");

    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
    // dialog title
    builder.setTitle(titleId);
    // dialog message
    builder.setMessage(messageId);

    // dialog negative button
    builder.setNegativeButton("No", new OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            receiver.sendResult(Activity.RESULT_CANCEL, null);
        }});
    // dialog positive button
    builder.setPositiveButton("Yes", new OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            receiver.sendResult(Activity.RESULT_OK, null);
        }});

    // create the Dialog object and return it
    return builder.create();
}}

Then you can handle everything in the Receiver like this:

protected void onReceiveResult(int resultCode, Bundle resultData) {
    if (getActivity() != null){
        // Handle result
    }
}

Check out ResultReceiver doesn't survire to screen rotation for more details. So in the end you probably still need to rewire the ResultReceiver with your Activity. The only difference is that you decouple the Activity from the DialogFragment.

Tuesday, September 7, 2021
 
Ula
answered 3 Months ago
Ula
18

No, if the positive direction of Z points to the sky then when y axis points to West then the angle is positive. But the coordinate used in getOrientation the positive direction of Z points down to the earth, thus now what seems counter-clockwise becomes clockwise, so West is negative.

Wednesday, November 17, 2021
 
dougv
answered 3 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share