Passing a listener to a custom Fragment in Android
I suppose you want to re-use the Fragment
with various different listeners. So your approach is not ideal since you can not use the Bundle
for that. A better approach would be to use the callback design pattern e.g.
public class RegWizardFragmentInfo extends Fragment {
public interface RegWizardCallback {
void onClick();
}
}
Your Activity
would implement that interface. Since a Fragment
only lives inside an Activity you can get the callback instance from it by using the lifecycle method onAttach()
. It would look like this
public class RegWizardFragmentInfo extends Fragment {
private RegWizardCallback callback;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
callback = (RegWizardCallback) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement RegWizardCallback ");
}
}
public interface RegWizardCallback {
void onClick();
}
}
With that you can simply call callback.onClick
inside the listener of the Button.
You can use a callback in your Fragment
:
public class RegWizardFragmentInfo extends Fragment {
private Button button;
private OnClickCallback callback;
public interface OnClickCallback {
void onClick();
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
callback = (OnClickCallback) context;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
callback.onClick();
}
});
}
}
and implement this new interface in your parent Activity
The other answers assign the listener in onAttach
. While this will work, it requires that the calling Activity
(and not, say, an anonymous class) implement your interface. Moreover, it forces you to cast the Context
given to you in onAttach
to an instance of your interface, which can cause crashes and is generally considered bad form. You might instead create a method to set the listener inside your Fragment
:
public class RegWizardFragmentInfo extends Fragment {
private OnClickListener mListener;
public interface OnClickListener {
void onClick();
}
/**
* Call at any time after this fragment has been constructed.
*/
public void setListener(OnClickListener listener) {
mListener = listener;
}
/* ...other stuff... */
}
I can think of three disadvantages to this approach:
- You need to call an extra method every time you want to instantiate the
Fragment
. - You can't guarantee that
mListener
is set at any time. You may need to pepper yourFragment
code with null checks. - You need to be careful to make sure the listener remains set after lifecycle events such as screen rotation.