I have a question about "proper programming" in Android.
I am currently developing an app using fragments. It involves dynamically added fragments to Activity, fragments inflated from XML, nested fragments from XML or dynamically added. Let's just say, a bit of everything.
The concept this question focuses on is the communication process involved with fragments. So, I've read the docs and this is not the first time I try to use fragments.
The common sense (and docs) tell that if a Fragment wants to speak or communicate with it's activity, we should use an interface.
Example:
TestFragment
public class TestFragment extends Fragment {
private TestFragmentInterface listener;
public interface TestFragmentInterface {
void actionMethod();
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
if (getActivity() instanceof TestFragmentInterface) {
listener = (TestFragmentInterface) getActivity();
}
// sending the event
if (listener != null) listener.actionMethod();
}
}
TestActivity
public class Test implements TestFragmentInterface {
@Override
public void actionMethod() {
..
}
}
Everything fine here.
This improves re-usability, as my TestFragment this way can interact with any kind of Activity, given the Activity implements the interface I declare.
The other way around, the Activity can interact with the fragment by holding a reference and calling its public methods. This is also the suggested way to fragment-to-fragment communication, using the Activity as a bridge.
This is cool, but sometimes it feels like using an interface for this is just a bit "too much".
Question A
In the scenario the fragments I attach have a pretty focused role, meaning they are done for that particular activity and would not be used otherwise, is it conceptually wrong to ignore the interface implementation and just do something like
((TestActivity) getActivity().myCustomMethod();
?
This also goes to the scenario where (not my case, but just taking it as a "at its worst") my activity has to deal with a wide variety of these DIFFERENT fragments, meaning it should implement one method for every fragment it should handle. This brings the code to a big mess of "potentially not-needed lines".
Moving further on: still with the use of "focused" fragments, aimed to work only under certain way, what is with the use of nested fragments?
Added them like
public class TestFragment extends Fragment {
private void myTestMethod() {
NestedFragment nested = new NestedFragment();
getChildFragmentManager()
.beginTransaction()
.add(R.id.container, nested)
.commit();
}
}
this binds NestedFragment to TestFragment. I say it again, NestedFragment, just like TestFragment, is to be used only in this way, it has no meaning to work otherwise.
Back to the question, how should I behave in this situation?
Question B
1) should I provide an interface in NestedFragment, and make so that TestFragments implements NestedFragmentInterface? In this case I would act as following
NestedFragment
public class NestedFragment extends Fragment {
private NestedFragmentInterface listener;
public interface NestedFragmentInterface {
void actionMethodNested();
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
if (getParentFragment() instanceof NestedFragmentInterface) {
listener = (NestedFragmentInterface) getParentFragment();
}
// sending the event
if (listener != null) listener.actionMethodNested();
}
}
2) should (or could) I ignore interface, and just call
getParentFragment().publicParentMethod();
?
3) should I create the interface in NestedFragment, but let the activity implements it, so that the activity will call TestFragment ?
Question C
Regarding the idea of using the Activity as a bridge between fragments, I believe it is made so for proper handling lifecycle of all these objects. Is it still viable to do a direct fragment-to-fragment (using interface or directly call public methods) while trying to handle manually the exception the system might throw me?
I will try to clear it all a little bit.
First of all, consider you approach of setting listener for fragment. It is no good to set listener in onViewCreated method, because it leeds to excess reseting listener any fragment is created. It is enough to set it up into onAttach method.
I told about code lines. Take me to notice, it is good to have BaseFragment implemented common behavior in you app as setting FragmentListener creating view from resource.
And more than that to reduce code lines and to get part of code reuse you can use generic in BaseFragment. So look at next code snippet:
Answer A (For Question A):
If you have fragment only exactly one activity you need to decide: "Do you really need to use Fragment here?". But mb it is good to have fragment exactly for one activity to extract some view logic from activity and clearing base logic. But for clearing base architecture logic for your app use Listeners. This will make life easier for other developers
Answer B: For nested fragments you need to solve, what they need to use exact activity or just fragments and use it as a bridge to other system. If you know that nested fragment will be nested all time you, you need to declare parent fragment as listener otherwise you have to use other approach.
Notice: As the base approach to communicate between diff part of App you can use events, try too look at event bus for example. It gives you common approach for communication and you can extract logic of calling custom methods of listeners and more another, all logic will be situated into handling events and you will have one mediator system for cooperation.
Answer C: I partially explain one of approaches to cooperating between fragments. Using one event dispatcher avoids you to have many listeners for all different communication. Some times it is very profitably.
Or I think it is more usable to use Activity, or other class lives in Activity, for a mediator for Fragments cooperation because there is many situation of Fragments changing during lifecycle both handling and system. And it focuses all this logic in one place and makes your code more clear.
Hope my considerations helps you.