Actually I had requirement on my project that was impossible to finish without this "genius" idea because of some ugly legacy code written by other developer (sure it was not me, my code is perfect :-D).
After digging support library for some time and implementing my own FragmentManager and FragmentTransaction I noticed one important detail - there is no need to reinvent a weal, it was already invented by Android's team. All I had to do is to look at FragmentActivity and find the FragmentController (silly me, I had to look there from the beginning). One interesting thing is that FragmentController is a public class which [in theory] means that we can safely use it.
Ok, so no more talk. Here is my implementation of FragmentManagerView:
public class FragmentManagerView extends FrameLayout { private Activity mActivity; private FragmentController mFragments; private Handler mHandler = new Handler(Looper.getMainLooper()); public FragmentManagerView(Context context) { this(context, null); } public FragmentManagerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); while (context != null) { if (context instanceof Activity) { mActivity = (Activity) context; break; } if (context instanceof ContextWrapper) { context = ((ContextWrapper) context).getBaseContext(); } else { break; } } setId(getFragmentRootId()); mFragments = FragmentController.createController(new HostCallbacks()); mFragments.attachHost(null); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); mFragments.dispatchCreate(); mFragments.dispatchActivityCreated(); mFragments.onCreateView(this, "", getContext(), null); mFragments.dispatchStart(); mFragments.dispatchResume(); mFragments.execPendingActions(); } @Override protected void onDetachedFromWindow() { mFragments.execPendingActions(); mFragments.dispatchPause(); mFragments.dispatchStop(); mFragments.dispatchReallyStop(); mFragments.dispatchDestroyView(); mFragments.dispatchDestroy(); super.onDetachedFromWindow(); } public int getFragmentRootId() { return android.R.id.content; } public FragmentManager getFragmentManager() { return mFragments.getSupportFragmentManager(); } private class HostCallbacks extends FragmentHostCallback<FragmentManagerView> { HostCallbacks() { super(mActivity, mActivity, mHandler, 0); } @Override public boolean onHasView() { return true; } @Override public View onFindViewById(int id) { return findViewById(id); } @Override public FragmentManagerView onGetHost() { return FragmentManagerView.this; } @Override public LayoutInflater onGetLayoutInflater() { return mActivity.getLayoutInflater().cloneInContext(mActivity); } } }
And this is how you can use it:
public class MyInnovativeView extends FragmentManagerView { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); getFragmentManager().beginTransaction() .replace(getFragmentRootId(), MyFragment.newInstance()) .commit(); } } public class MyFragment extends Fragment { // ... }
It works almost flawlessly. This solution even works for popup windows and dialogs. But there are still few drawbacks (actually those are all downsides that I found so far):
- getActivity() returns null in all fragments
This one is what I actually don't understand. FragmentHostCallback has constructor to provide activity (which then will be returned via Fragment.getActivity()) but it has package access. Same for FragmentHostCallback.getActivty() method. Because of this you can't legitimately use it.
But where is a will, there is a way!
We only need to place our FragmentManagerView in android.support.v4.app and by magic of great Java we'll get required access. - no state saving
It can be easily implemented using FragmentController.saveAllState() / View.onSaveInstanceState() and View.onRestoreInstanceState() / FragmentController.restoreAllState()
And now few final words - DON'T USE IT
- Yes, I used it on my project.
- Yes, all required classed are available and public.
- No, it does mean that you can safely use it and it will work for all cases.
- No, I don't know if this API was designed for such cases.
- No, there are no quranties that nothing will be changed in the future.
And most importantly
- Don't code in ways that force you to use solutions like this.
Have a nive coding ;)