4

I have an Activity that is largely unmodified form the default Android Studio example for a tabbed activity. Its FragmentPagerAdapter is modified to display all 50 United States, with 50 corresponding tabs displaying their names. This works until a fragment is destroyed, but when it's re-created, it's not told which tab it's on. Why does this happen?

The following are all the methods that I think could be part of the problem:

public class MainQuizActivity extends Activity implements ActionBar.TabListener {

    ...

    public class SectionsPagerAdapter extends FragmentPagerAdapter {

        ...

        @Override
        public Fragment getItem(int position) {
            // getItem is called to instantiate the fragment for the given page.
            // Return a PlaceholderFragment (defined as a static inner class below).
            return
                questionFragments[position] == null
                    ? questionFragments[position] = QuestionFragment.newInstance(position)
                    : questionFragments[position];
        }

        ...
    }

    ...
}

...

public class QuestionFragment extends Fragment {

    ...

    public static QuestionFragment newInstance(int stateIndex) {
        System.out.println("Creating new instance for state #" + stateIndex);
        QuestionFragment fragment = new QuestionFragment();
        Bundle args = new Bundle();
        args.putInt(States.BUNDLE_KEY, stateIndex);
        fragment.setArguments(args);
        return fragment;
    }

    ...

    @Override
    public View onCreateView(
        LayoutInflater inflater,
        ViewGroup container,
        Bundle savedInstanceState) {
        System.out.println("~onCreateView");
        View rootView = inflater.inflate(
            R.layout.fragment_main_quiz, container, false);

        webView = (WebView)rootView.findViewById(R.id.webView);
        initState(savedInstanceState);

        return rootView;
    }

    private void initState(Bundle args) {
        if (state == null) {
            System.out.println("Bundle: " + args);
            if (args == null)
                args = getArguments();
            System.out.println("Bundle is now: " + args);
            int stateIndex = args.getInt(States.BUNDLE_KEY);
            System.out.println("Gonna be state #" + stateIndex);
            state = States.values()[stateIndex];
            System.out.println("Gonna be " + state);
        }
        else
            System.out.println("State already exists! (yay!)");

        String path = state.getImageURL();
        System.out.println("Opening image at " + path);

        webView.loadUrl(path);
        webView.setBackgroundColor(0x00000000);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        System.out.println("~onCreate");
        super.onCreate(savedInstanceState);
        if (webView == null)
            webView = (WebView)(getActivity().findViewById(R.id.webView));
        System.out.println("onCreate: webView == " + webView);
        System.out.println("onCreate: bundle == " + savedInstanceState);

        if (webView != null
            && savedInstanceState != null)
        initState(savedInstanceState);
    }

    ...

}

I saved this in the bundle with the key States.BUNDLE_KEY (which is "STATE"), but the bundle it's given does not have that key in it the second time. For debugging purposes, I overrode all on* methods that deal with loading and unloading with empty ones like:

@Override public void onResume(){
    System.out.println("~onResume");
    super.onResume();}

Of course, there are also more debugging outputs that I threw in.

I hope this video I recorded helps illustrate the issue: http://youtu.be/cmbR_2rvpX4

The console dump for the video is in this pastebin: http://pastebin.com/rxAP7qda

And, if all this still doesn't help, here's its git: https://github.com/Supuhstar/US-State-Quiz-App


Even after all this, I feel I'm not giving the right information. Please ask for less or more if you think this can be put better.

Ky -
  • 30,724
  • 51
  • 192
  • 308
  • You haven't implemented any logic for saving/restoring the tab selection in the `Activity` saved state... – corsair992 Aug 01 '14 at 14:47
  • 2
    There isn't any reason for calling `initState(savedInstanceState);` in both `onCreate()` and `onCreateView()`(use only `onCreateView()`). Also, you should never look for the views of a fragment through `getActivity.findViewById()` especially if you use multiple instance of that fragment(like you do). – user Aug 01 '14 at 14:52
  • Alright, so what can I do to fix this? – Ky - Aug 01 '14 at 15:23
  • Remove the fragment's `onCreate` callback and make the changes to the fragment that I made here https://gist.github.com/luksprog/92720adc1b2f26390f5a . See how it goes. – user Aug 01 '14 at 15:35
  • @Luksprog Well that fixed all my problems! Put that as an answer! – Ky - Aug 01 '14 at 15:53

1 Answers1

3

You're not initializing things properly in your QuestionFragment. First of all there's no need to call the initState(savedInstanceState); method in both the onCreate() and onCreateView() callbacks. Call it in onCreateView() and remove entirely the onCreate() method:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    System.out.println("~onCreateView");
    View rootView = inflater.inflate(R.layout.fragment_main_quiz, container, false);

    webView = (WebView)rootView.findViewById(R.id.webView);
    guessSpinner = (Spinner)getActivity().findViewById(R.id.guess_spinner);
    initState();
    initGuesser();
    return rootView;
}

Your initState(savedInstanceState) method is also a bit too complicated for what it should do:

private void initState() {
     Bundle args = getArguments();
     if (args == null) {
        throw new IllegalArgumentException("The arguments should be valid!");
     }
     System.out.println("Bundle is now: " + args);
     int stateIndex = args.getInt(States.BUNDLE_KEY); 
     System.out.println("Gonna be state #" + stateIndex);
     state = States.values()[stateIndex];
     System.out.println("Gonna be " + state);
     String path = state.getImageURL();
     System.out.println("Opening image at " + path);

     webView.loadUrl(path);
     webView.setBackgroundColor(getResources().getColor(R.color.transparent));
}
user
  • 86,916
  • 18
  • 197
  • 190