Listen Dialog Positive button click in each ViewPager fragment

Viewed 291

I'm testing a function of listening the AlertDialog button click (Positive & Neutral) in each ViewPager fragment. And I am using the Interface method right now but getting some troubles.

So the structure is like this, I have an AlertDialog created by DialogFragment, and I put a ViewPager with two fragments into this DialogFragment. My goal is, when I click on the Positive button on the AlertDialog, I want some methods inside those two ViewPager fragments get called so that I can collect the data on those fragments.

Now the problem is, only the second fragment responses, I don't know why.

Here are the codes:

  1. I created an Interface file

    public interface Communicator {
        void onConfirmClick();
    }
    
  2. I have a DialogFragment

    public class MainDialogFragment extends DialogFragment {
        View dialogLayout;
        Communicator communicator;
    
        @Override
        public void onAttachFragment(Fragment childFragment) {
            communicator = (Communicator) childFragment;
        }
    
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            return dialogLayout;
        }
    
        @NonNull
        @Override
        public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
            AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity());
            dialogLayout = getActivity().getLayoutInflater().inflate(R.layout.dialog_main, null);
            ViewPager viewPager = dialogLayout.findViewById(R.id.main_viewPager);
    
            final MainPagerAdapter adapter = new MainPagerAdapter(getChildFragmentManager());
            viewPager.setAdapter(adapter);
    
            dialogBuilder.setView(dialogLayout);
            dialogBuilder.setPositiveButton("Confirm", null);
            dialogBuilder.setNegativeButton("Cancel", null);
            dialogBuilder.setNeutralButton("Change", null);
    
            final AlertDialog dialog = dialogBuilder.create();
    
            dialog.setOnShowListener(new DialogInterface.OnShowListener() {
                @Override
                public void onShow(DialogInterface dialogInterface) {
                    dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            communicator.onConfirmClick();
                        }
                    });
    
            dialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            Toast.makeText(view.getContext(), "Change click!!", Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            });
    
            return dialog;
        }
    }
    
  3. My fragment A

    public class MainFragmentA extends Fragment implements Communicator{
        View rootView;
    
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            rootView = inflater.inflate(R.layout.fragment_a, container, false);
    
            return rootView;
        }
    
        @Override
        public void onConfirmClick() {
            Toast.makeText(getContext(), "Fragment A!!", Toast.LENGTH_SHORT).show();
        }
    }
    
  4. My fragment B

    public class MainFragmentB extends Fragment implements Communicator{
        View rootView;
    
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            rootView = inflater.inflate(R.layout.fragment_b, container, false);
    
            return rootView;
        }
    
        @Override
        public void onConfirmClick() {
            Toast.makeText(getContext(), "Fragment B!!", Toast.LENGTH_SHORT).show();
        }
    }
    
  5. My ViewPager adapter used inside DialogFragment

    public class MainPagerAdapter extends FragmentPagerAdapter {
        public MainPagerAdapter(FragmentManager fragmentManager) {
            super(fragmentManager);
        }
    
        @Override
        public Fragment getItem(int position) {
            switch (position) {
                case 0:
                    return new MainFragmentA();
    
                case 1:
                    return new MainFragmentB();
    
                default:
                    throw new IllegalArgumentException("Wrong position!!");
            }
        }
    
        @Override
        public int getCount() {
            return 2;
        }
    }
    
  6. My MainActivity

    public class MainActivity extends AppCompatActivity{
        Button showDialogButton;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            showDialogButton = findViewById(R.id.main_show_dialog_button);
    
            showDialogButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    MainDialogFragment mainDialogFragment = new MainDialogFragment();
                    mainDialogFragment.show(getSupportFragmentManager(), "mainDialogFragment");
                }
            });
        }
    }
    

Anyone can help? I'll so appreciate that!!!

2 Answers

Use a collection of some sort of Communicator interfaces instead of a single one. You're overwriting the communicator every time a child fragment is attached.

public class MainDialogFragment extends DialogFragment {
    View dialogLayout;
    List<Communicator> communicators = new ArrayList<>();

    @Override
    public void onAttachFragment(Fragment childFragment) {
        communicators.add((Communicator) childFragment);
    }

    // all the other things from the MainDialogFragment...
}

And in the BUTTON_POSITIVE callback iterate through the list.

dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
        for (Communicator communicator : communicators) { 
            communicator.onConfirmClick();
        }
    }
});

Only the communicator from the second fragment works

This is because you have two different instances of communicator in each of your fragments. As you are setting up the ViewPager, the second fragment is the last one that is being attached with the parent fragment. Hence, the communicator that you are initializing inside the onAttachFragment function of your MainDialogFragment class, is storing the reference from the second fragment only as this was the last one to be attached here.

In your case, I would rather suggest a very simple implementation using the lifecycle functions of the Fragment. Just take a public static variable in your MainDialogFragment class which will indicate if the okay button was clicked or not. And then check the value of that variable from each of your Fragment class inside the onResume function and perform the tasks accordingly. To get an idea of the implementation, please check the following.

Get a variable in your MainDialogFragment class like the following.

public static boolean isDialogOkayClicked = false; // Default false

Now in your MainFragmentA, implement the onResume function and check the value from the MainDialogFragment. Take the actions accordingly.

public class MainFragmentA extends Fragment implements Communicator{
    View rootView;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.fragment_a, container, false);

        return rootView;
    }

    @Override
    protected void onResume() {
        super.onResume();
        if(MainDialogFragment.isDialogOkayClicked) 
            doSomething();
    }

    @Override
    public void onConfirmClick() {
        Toast.makeText(getContext(), "Fragment A!!", Toast.LENGTH_SHORT).show();
    }
}

Do the same thing for your other fragment.

Hope that helps!

Related