How come position information isn't being passed to my fragments?
-
21-12-2019 - |
Question
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.
Solution
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));
}