Mohammad's original answer is close to I would do. He has since updated it to leverage a mechanism provided by Android - Fragment.onAttach(Context context)
.In that approach, the fragment grabs components (ie, the activity) from the system and calls into it. This breaks inversion of control.
Here is my preferred approach:
public class MyActivity extends AppCompatActivity {
@Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
if (fragment instanceof MyFragment) {
((MyFragment) fragment).setListener(mMyFragmentListener);
}
}
private final MyFragment.Listener mMyFragmentListener = new MyFragment.Listener() {
@Override
public void onDetached(MyFragment fragment) {
fragment.setListener(null);
}
// implement other worker methods.
};
}
public class MyFragment extends Fragment {
@Nullable
private Listener mListener;
public void setListener(@Nullable Listener listener) {
mListener = listener;
}
public interface Listener {
void onDetached(MyFragment fragment);
// declare more worker methods here that leverage the connection.
}
@Override
public void onDetach() {
super.onDetach();
if (mListener != null) {
mListener.onDetached(this);
}
}
}
In this solution, the fragment doesn't dictate it's surroundings. Some control is given the to fragment in that it breaks the connection itself. We also already don't own the detaching of the fragment anyways, so clearing the listener is really just cleanup.
Here is an alternative approach that is more explicit, less prone to developer error, but also creates extra boiler plate (I prefer the previous approach because the goodbye handshake feels like an unnecessary distraction):
public static class MyActivity extends AppCompatActivity {
@Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
if (fragment instanceof MyFragment) {
((MyFragment) fragment).setListener(mMyFragmentListener);
}
}
private final MyFragment.Listener mMyFragmentListener = new MyFragment.Listener() {
@Override
public void onDetached(MyFragment fragment) {
fragment.setListener(null);
}
// implement other worker methods.
};
}
public static class MyFragment extends Fragment {
@Nullable
private Listener mListener;
public void setListener(@Nullable Listener listener) {
mListener = listener;
}
public interface Listener {
void onDetached(MyFragment fragment);
// declare more worker methods here that leverage the connection.
}
@Override
public void onDetach() {
super.onDetach();
if (mListener != null) {
mListener.onDetached(this);
}
}
}