I was creating a fragment with a custom object this way:
public class SlideFragment extends Fragment {
SlideData data;
public static SlideFragment newInstance(SlideData data) {
SlideFragment fragment = new SlideFragment(data);
return fragment;
}
public SlideFragment() {
}
public SlideFragment(SlideData data) {
this.data = data;
}
...
}
But I realized that this is wrong and it crashes if Android recreates the fragment (it uses the default constructor so data is null).
Reading about this I've seen that I should do something like this:
public class SlideFragment extends Fragment {
SlideData data;
public static SlideFragment newInstance(SlideData data) {
SlideFragment fragment = new SlideFragment(data);
Bundle b = new Bundle();
b.putParcelable("data", data);
fragment.setArguments();
return fragment;
}
public SlideFragment() {
}
public SlideFragment(SlideData data) {
this.data = data;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View _fragment = inflater.inflate(R.layout.fragment_slide, container, false);
Bundle b = getArguments();
data = b.getParcelable("data");
return _fragment;
}
...
}
So I should make SlideData as a Parcelable Object, but the problem is that this object is a bit complex:
public class SlideData {
List<SlideMessageData> messages;
int backgroundColor;
SlideButtonType buttonType;
SlideButtonInterface listener;
}
public class SlideMessageData {
String text;
int textColour;
}
public enum SlideButtonType {
CLOSE,
PREVIOUS,
NEXT
}
public interface SlideButtonInterface {
void clickOnSlideButton();
}
To make this parcelable I was thinking to use:
- writeList and readList for "messages".
- writeInt and readInt for "backgroundColor" and "textColor".
- writeString and readString for "text".
- writeInt(buttonType.ordinal()) and SlideButtonType.values()[in.readInt()] for "buttonType".
But there is no way to make parcelable the "listener" attribute (it's normal, it's no sense).
So, how could I solve this problem? How could I make persistent my slidedata if the fragment is recreated by Android?
UPDATE:
Taking into account game over comment I've tried to subclass FragmentFactory class, but in this case I can't do it. I use FactoryFragment to create my fragments, but this case is special. I'm creating this fragment for a FragmentAdapter.
I have this:
public class SlideAdapter extends FragmentStatePagerAdapter {
...
public void addSlide(SlideData data)
{
SlideFragment slide = SlideFragment.newInstance(data);
listOfFragments.add(slide);
notifyDataSetChanged();
}
...
}
And this (I've added more data after game over comment):
public class SlideViewerFragment extends Fragment {
public static SlideViewerFragment newInstance() {
return new SlideViewerFragment();
}
public SlideViewerFragment() {
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null)
data = savedInstanceState.getBundle("data");
}
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBundle("data", data);
}
public void setData(Bundle _data)
{
data = _data;
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
FragmentActivity activity = getActivity();
FragmentManager fragmentManager = activity.getSupportFragmentManager();
mSlideAdapter = new SlideAdapter(fragmentManager);
adapter.setValue(mSlideAdapter);
slideList = viewModel.getSlideListData();
slideList.observe(myActivity, this::slideListChanged);
return view;
}
private void buildSlides() {
mSlideAdapter.clearSlides();
for(int index = 0; index < slides.size(); index++)
{
SlideData slide = slides.get(index);
mSlideAdapter.addSlide(slide);
}
}
...
}
And I'm creating my SlideViewerFragment this way:
final FragmentManager fm = getSupportFragmentManager();
FragmentFactory ff = fm.getFragmentFactory();
Fragment fr = ff.instantiate(getClassLoader(), SlideViewerFragment.class.getName());
FragmentTransaction ft = fm.beginTransaction();
ft.setReorderingAllowed(true);
ft.add(R.id.frame_content, fr, SlideViewerFragment.class.getName());
Bundle _data = new Bundle();
_data.putInt("content_type", 2);
((BaseFragment) fr).setData(_data);
ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);
ft.commit();
fm.executePendingTransactions();
Since I'm not using here a FragmentFactory, how could I recreate my SlideFragment in a safe manner?
Maybe the problem is in how I'm building SlideViewerFragment using instantiate? Should I use SlideViewerFragment.newInstance(data) and subclass FragmentFactory to create SlideViewerFragment using the constructor with arguments?