2

When my Activity makes a Volley request, I show a dialog with a dialog fragment. And in the response handler, which is a non-static inner class of the Activity, I dismiss the dialog fragment with:

@Override
public void onResponse(String response) {
    MyActivity.this.takeAwayTheDialog();
}

Things work fine unless I rotate the device. If the response comes back after the orientation change completes, MyActivity.this has already been destroyed.

Possible solutions include:

  1. Cancel the request before the orientation change
  2. Use a separate retained fragment to handle the network request

But they do not look satisfactory. I'd like to have a solution that allows the system to handle the orientation for me so that the activity is recreated and the correct resources are loaded. Can anyone comment on the two solutions above or give other suggestions? Thx.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Jonas
  • 534
  • 8
  • 16
  • In your manifest for the particular activity, you can define ` android:configChanges="orientation"`. So, that it won't restart the activity. – Nigam Patro Jun 25 '16 at 08:17
  • You can easily override the `onOrientationChanged` function to make necessary changes you want to make after a change in orientation. You may have the request called again after stopping the previous volley request. – Reaz Murshed Jun 25 '16 at 08:48
  • @NigamPatro , please avoid using `android:configChanges="orientation"`. From the [docs](https://developer.android.com/guide/topics/manifest/activity-element.html#config) , *Using this attribute should be avoided and used only as a last resort* , have a look at [this](http://stackoverflow.com/a/7990543/2666212) answer for details. – Mike Jun 25 '16 at 09:14
  • Just to be sure, Are you using `FragmentManager` to show the dialog? so that it will survive the configuration change. – Mike Jun 25 '16 at 10:48
  • @Mike. Before I start the network request, I show a dialog with `myDialogFragment.show(getFragmentManager(), TAG);`. I call this in a support fragment, but I mentioned I was using an `Activity` in the question. My bad... – Jonas Jun 25 '16 at 10:51

1 Answers1

0

Since nobody has answered this yet, I will write my opinion in your solutions:

  1. Canceling the request before the orientation change (maybe in onPause() of your activity) and re-initiating it after the orientation change (maybe in onResume()) can be a quick working solution, but it may end you up sending the request twice to the server.

    This is not usually a problem, but if the request is a POST request that signs the user up for example, that can cause the user to get the error that the username already exists after the orientation change (since the first activity has signed it up to the server successfully, and the second activity is trying to sign him/her up again).

    if sending the request twice is not a problem for you, this solution works quiet good, since Volley may transparently cache the response of the first request for you(if the server sends the right headers), and the second request will get the response as if you have a super-fast connection. . .

  2. Using a retained headless fragment, initiating the the Volley request from within it, and having callbacks into your current activity works pretty good, and I think that it does allow the system to handle the orientation for you so that the activity is recreated and the correct resources are loaded, and after that the current activity gets the response and shows it to the user.

    The only downside I can think of in this solution is that it requires much boilerplate code to be written, Here's how you may use this approach to display the dialog and hide it.

    public class MainActivity extends AppCompatActivity{
    
        public static class MainActivityHeadlessFragment extends Fragment {
    
            private MainActivity mActivity;
            public MainActivityHeadlessFragment() {
                // Required empty public constructor
            }
    
    
    
            @Override
            public void onCreate(@Nullable Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setRetainInstance(true);
            }
    
            public void ShowDialog() {
                DialogFragment newFragment = SampleDialogFragment.newInstance();
                newFragment.show(mActivity.getSupportFragmentManager(), "sample_dialog_tag");
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        Fragment f = mActivity.getSupportFragmentManager().findFragmentByTag("sample_dialog_tag");
                        if(f!= null){
                            DialogFragment df = (DialogFragment) f;
                            df.dismiss();
                        }
                    }
                }, 5000);
            }
    
            @Override
            public void onAttach(Context context) {
                super.onAttach(context);
                if (context instanceof MainActivity) {
                    mActivity= (MainActivity) context;
                } else {
                    throw new RuntimeException(context.toString()
                            + " MainActivityHeadlessFragment can only be used with MainActivity");
                }
            }
    
            @Override
            public void onDetach() {
                super.onDetach();
                mActivity= null;
            }
        }
    
        private MainActivityHeadlessFragment mDataFragment;
        private MainFragment mFragment;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            FragmentManager fm = getSupportFragmentManager();
            mDataFragment = (MainActivityHeadlessFragment) fm.findFragmentByTag("data_fragment");
    
            // If the Fragment is non-null, then it is currently being
            // retained across a configuration change.
            if (mDataFragment == null) {
                mDataFragment = new MainActivityHeadlessFragment();
                fm.beginTransaction().add(mDataFragment, "data_fragment").commit();
            }
        }
    
    
    
        public void ShowDialog(View v){
            mDataFragment.ShowDialog();
        }
    }
    

    For simplicity, I have replaced the Volley request with a new Handler().postDelayed() but the idea should be the same. . .

Mike
  • 8,055
  • 1
  • 30
  • 44