How to call a method in a fragment through the onClick in another fragment?

Andros Adrianopolos :

I am building an app with 2 fragments. The 1st fragment has an ImageView and 2 TextViews and the 2nd fragment has a set of buttons and EditTexts. In the 2nd fragment, I have a button called "Save". When this button is clicked, I want to download the image inside my 1st fragment to my device folder (The ImageView, the URI, the bitmap and canvas objects are all in the 1st fragment).

Because fragments can't communicate with one another directly, I was thinking of doing this with an interface. What I did was:

  • I've declared my interface in the 2nd fragment
  • Applied the logic of the interface's method in the MainActivity (which is the shared activity between the 2 fragments)
  • Fed the necessary parameters for the method in the 1st fragment.
  • Didn't work

But I don't think that this was the correct order so it's no surprise that it didn't work. How do I apply the interface in a way that a button click in the 2nd fragment downloads the image in the 1st fragment?

Sandrogo :

You could try one of these three options:

1.) Using callbacks to communicate via the activity

As shown in this article, you can define an interface in fragment 2 which is then called when the button is clicked. Your activity (which holds fragment 2) provides an implementation for that interface in which the activity calls a method in fragment 1 for downloading the image. For example:

Fragment 1 providing the download method

public class Fragment1 extends Fragment {
    OnButtonClickedListener mCallback;

    public void startImageDownload() {
        // Download the image
    }

    // ...
}

Fragment 2 defining and calling the interface

public class Fragment2 extends Fragment {
    OnButtonClickedListener mCallback;

    // Some kind of init method called by onCreate etc. 
    private void init() {
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Call the listener if present
                if(mCallback != null) {
                    mCallback.onButtonClicked();
                }
            }
        });
    }

    public void setOnButtonClickedListener(Activity activity) {
        mCallback = activity;
    }

    // Container Activity must implement this interface
    public interface OnButtonClickedListener {
        public void onButtonClicked();
    }

    // ...
}

The Activity reacting on the Button click and calling the download method

public static class MainActivity extends Activity implements Fragment2.OnButtonClickedListener {
    Fragment1 mFragment1;

    @Override
    public void onAttachFragment(Fragment fragment) {
        if (fragment instanceof Fragment2) {
            // Register the listener
            Fragment2 fragment2 = (Fragment2) fragment;
            fragment2.setOnButtonClickedListener(this);
        } else if (fragment instanceof Fragment1) {
            // Keep a reference to fragment 1 for calling the "download" method
            mFragment1 = (Fragment1) fragment;
        }
    }

    @Override
    public void onButtonClicked() {
        // Handle the button click
        mFragment1.startImageDownload();
    }
}

This way you avoid linking the fragments together, instead you have the activity beeing a loose "connection" between fragment 1 and fragment 2.

This is just an exmple, i did not had time to test it. But i hope it helps.

2.) Using a local broadcast

I would recommend using the LocalBroadcastManager for sending a broadcast in fragment 1 (that the button was clicked) and receiving it in fragment 2 (downloading the image). Here is a great article about local broadcasts.

3.) Another option is to use ViewModel

The ViewModel was recently introduced by the new Android Jetpack and "is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations." (from ViewModel Overview).

It can also be used to share data between two fragments: Your activity basically holds the ViewModel and the fragments (inside that activity) can get access to it by calling: ViewModelProviders.of(getActivity()).get(SharedViewModel.class); I think your scenario you could use Observers or some kind of LiveData to react to the button-click via a ViewModel.

Thanks to @Elletlar for helping me improve my answer.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=146120&siteId=1