Passing listener to user fragment in Android

I create a view pager in my application and use a class that extends the fragment on it. When I create an instance, I can transfer all the elements (image, text, etc.) and save it using the Bundle to use it in onCreate. But I can not store the button listener in the fragment. Here is my class:

public class RegWizardFragmentInfo extends Fragment { private static final String IMAGE = "image"; private static final String TEXT = "text"; private static final String BUTTON = "buttonText"; private View.OnClickListener buttonCallBack; private Button button; private int image; private int text; private int buttonText; public RegWizardFragmentInfo newInstance(int image, int text, int buttonText, View.OnClickListener callback) { RegWizardFragmentInfo fragment = new RegWizardFragmentInfo(); Bundle bundle = new Bundle(); bundle.putInt(IMAGE, image); bundle.putInt(BUTTON, buttonText); bundle.putInt(TEXT, text); fragment.setArguments(bundle); fragment.setRetainInstance(true); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); super.onActivityCreated(savedInstanceState); this.image = getArguments().getInt(IMAGE); this.text = (getArguments() != null) ? getArguments().getInt(TEXT) : -1; this.buttonText = (getArguments() != null) ? getArguments().getInt(BUTTON) : -1; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ViewGroup rootView = (ViewGroup) inflater.inflate( R.layout.fragment, container, false); //Extract all the views and add the image and texts return rootView; } 

So, how can I save the listener that I get in newInstance to add it to the button onCreateView method?

Thanks for the help.

+5
source share
3 answers

You can use the callback in 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 the parent Activity

+1
source

Suppose you want to reuse Fragment with various listeners. So your approach is not ideal, as you cannot use the Bundle for this. A better approach would be to use a callback pattern, for example.

 public class RegWizardFragmentInfo extends Fragment { public interface RegWizardCallback { void onClick(); } } 

Your Activity will implement this interface. Since Fragment lives only inside an Activity, you can get a callback instance from it using the onAttach() lifecycle method. It will look like

 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 this, you can simply call callback.onClick inside the button listener.

+1
source

Other responses are assigned to the listener in onAttach . Although this will work, it requires the calling Activity (and not, say, an anonymous class) to implement your interface. In addition, it forces you to discard the Context provided to you in onAttach by an instance of your interface, which can lead to crashes and is usually considered bad. I would just 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 imagine two drawbacks for this approach:

  • You need to call an additional method every time you want to instantiate a Fragment .
  • You cannot guarantee that mListener installed at any time. You may need to migrate the Fragment code with null checks.

But, in my opinion, these problems are insignificant in comparison with the flexibility this approach gives the calling code.

0
source

Source: https://habr.com/ru/post/1272365/


All Articles