Basic communication between two fragments

前端 未结 10 2153
我寻月下人不归
我寻月下人不归 2020-11-22 05:00

I have one activity - MainActivity. Within this activity I have two fragments, both of which I created declaratively within the xml.

I am trying to pas

相关标签:
10条回答
  • 2020-11-22 05:21

    The nicest and recommended way is to use a shared ViewModel.

    https://developer.android.com/topic/libraries/architecture/viewmodel#sharing

    From Google doc:

    public class SharedViewModel extends ViewModel {
    private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
    
    public void select(Item item) {
        selected.setValue(item);
    }
    
    public LiveData<Item> getSelected() {
        return selected;
    }
    }
    
    
    public class MasterFragment extends Fragment {
    private SharedViewModel model;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
    }
    
    
    public class DetailFragment extends Fragment {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, { item ->
           // Update the UI.
        });
    }
    }
    

    ps: two fragments never communicate directly

    0 讨论(0)
  • 2020-11-22 05:23

    Have a look at the Android developers page: http://developer.android.com/training/basics/fragments/communicating.html#DefineInterface

    Basically, you define an interface in your Fragment A, and let your Activity implement that Interface. Now you can call the interface method in your Fragment, and your Activity will receive the event. Now in your activity, you can call your second Fragment to update the textview with the received value

    Your Activity implements your interface (See FragmentA below)

    public class YourActivity implements FragmentA.TextClicked{
        @Override
        public void sendText(String text){
            // Get Fragment B
            FraB frag = (FragB)
                getSupportFragmentManager().findFragmentById(R.id.fragment_b);
            frag.updateText(text);
        }
    }
    

    Fragment A defines an Interface, and calls the method when needed

    public class FragA extends Fragment{
    
        TextClicked mCallback;
    
        public interface TextClicked{
            public void sendText(String text);
        }
    
        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
    
            // This makes sure that the container activity has implemented
            // the callback interface. If not, it throws an exception
            try {
                mCallback = (TextClicked) activity;
            } catch (ClassCastException e) {
                throw new ClassCastException(activity.toString()
                    + " must implement TextClicked");
            }
        }
    
        public void someMethod(){
            mCallback.sendText("YOUR TEXT");
        }
    
        @Override
        public void onDetach() {
            mCallback = null; // => avoid leaking, thanks @Deepscorn
            super.onDetach();
        }
    }
    

    Fragment B has a public method to do something with the text

    public class FragB extends Fragment{
    
        public void updateText(String text){
            // Here you have it
        }
    }
    
    0 讨论(0)
  • 2020-11-22 05:23

    Take a look at https://github.com/greenrobot/EventBus or http://square.github.io/otto/

    or even ... http://nerds.weddingpartyapp.com/tech/2014/12/24/implementing-an-event-bus-with-rxjava-rxbus/

    0 讨论(0)
  • 2020-11-22 05:25

    I give my activity an interface that all the fragments can then use. If you have have many fragments on the same activity, this saves a lot of code re-writing and is a cleaner solution / more modular than making an individual interface for each fragment with similar functions. I also like how it is modular. The downside, is that some fragments will have access to functions they don't need.

        public class MyActivity extends AppCompatActivity
        implements MyActivityInterface {
    
            private List<String> mData; 
    
            @Override
            public List<String> getData(){return mData;}
    
            @Override
            public void setData(List<String> data){mData = data;}
        }
    
    
        public interface MyActivityInterface {
    
            List<String> getData(); 
            void setData(List<String> data);
        }
    
        public class MyFragment extends Fragment {
    
             private MyActivityInterface mActivity; 
             private List<String> activityData; 
    
             public void onButtonPress(){
                  activityData = mActivity.getData()
             }
    
            @Override
            public void onAttach(Context context) {
                super.onAttach(context);
                if (context instanceof MyActivityInterface) {
                    mActivity = (MyActivityInterface) context;
                } else {
                    throw new RuntimeException(context.toString()
                            + " must implement MyActivityInterface");
                }
            }
    
            @Override
            public void onDetach() {
                super.onDetach();
                mActivity = null;
            }
        } 
    
    0 讨论(0)
  • 2020-11-22 05:27

    There is a simple way to implement communication between fragments of an activity using architectural components. Data can be passed between fragments of an activity using ViewModel and LiveData.

    Fragments involved in communication need to use the same view model objects which is tied to activity life cycle. The view model object contains livedata object to which data is passed by one fragment and the second fragment listens for changes on LiveData and receives the data sent from fragment one.

    For complete example see http://www.zoftino.com/passing-data-between-android-fragments-using-viewmodel

    0 讨论(0)
  • 2020-11-22 05:28

    Some of the other examples (and even the documentation at the time of this writing) use outdated onAttach methods. Here is a full updated example.

    Notes

    • You don't want the Fragments talking directly to each other or to the Activity. That ties them to a particular Activity and makes reuse difficult.
    • The solution is to make an callback listener interface that the Activity will implement. When the Fragment wants to send a message to another Fragment or its parent activity, it can do it through the interface.
    • It is ok for the Activity to communicate directly to its child fragment public methods.
    • Thus the Activity serves as the controller, passing messages from one fragment to another.

    Code

    MainActivity.java

    public class MainActivity extends AppCompatActivity implements GreenFragment.OnGreenFragmentListener {
    
        private static final String BLUE_TAG = "blue";
        private static final String GREEN_TAG = "green";
        BlueFragment mBlueFragment;
        GreenFragment mGreenFragment;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // add fragments
            FragmentManager fragmentManager = getSupportFragmentManager();
    
            mBlueFragment = (BlueFragment) fragmentManager.findFragmentByTag(BLUE_TAG);
            if (mBlueFragment == null) {
                mBlueFragment = new BlueFragment();
                fragmentManager.beginTransaction().add(R.id.blue_fragment_container, mBlueFragment, BLUE_TAG).commit();
            }
    
            mGreenFragment = (GreenFragment) fragmentManager.findFragmentByTag(GREEN_TAG);
            if (mGreenFragment == null) {
                mGreenFragment = new GreenFragment();
                fragmentManager.beginTransaction().add(R.id.green_fragment_container, mGreenFragment, GREEN_TAG).commit();
            }
        }
    
        // The Activity handles receiving a message from one Fragment
        // and passing it on to the other Fragment
        @Override
        public void messageFromGreenFragment(String message) {
            mBlueFragment.youveGotMail(message);
        }
    }
    

    GreenFragment.java

    public class GreenFragment extends Fragment {
    
        private OnGreenFragmentListener mCallback;
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View v = inflater.inflate(R.layout.fragment_green, container, false);
    
            Button button = v.findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String message = "Hello, Blue! I'm Green.";
                    mCallback.messageFromGreenFragment(message);
                }
            });
    
            return v;
        }
    
        // This is the interface that the Activity will implement
        // so that this Fragment can communicate with the Activity.
        public interface OnGreenFragmentListener {
            void messageFromGreenFragment(String text);
        }
    
        // This method insures that the Activity has actually implemented our
        // listener and that it isn't null.
        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            if (context instanceof OnGreenFragmentListener) {
                mCallback = (OnGreenFragmentListener) context;
            } else {
                throw new RuntimeException(context.toString()
                        + " must implement OnGreenFragmentListener");
            }
        }
    
        @Override
        public void onDetach() {
            super.onDetach();
            mCallback = null;
        }
    }
    

    BlueFragment.java

    public class BlueFragment extends Fragment {
    
        private TextView mTextView;
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View v = inflater.inflate(R.layout.fragment_blue, container, false);
            mTextView = v.findViewById(R.id.textview);
            return v;
        }
    
        // This is a public method that the Activity can use to communicate
        // directly with this Fragment
        public void youveGotMail(String message) {
            mTextView.setText(message);
        }
    }
    

    XML

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="16dp">
    
        <!-- Green Fragment container -->
        <FrameLayout
            android:id="@+id/green_fragment_container"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:layout_marginBottom="16dp" />
    
        <!-- Blue Fragment container -->
        <FrameLayout
            android:id="@+id/blue_fragment_container"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />
    
    </LinearLayout>
    

    fragment_green.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:orientation="vertical"
                  android:background="#98e8ba"
                  android:padding="8dp"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent">
    
        <Button
            android:id="@+id/button"
            android:text="send message to blue"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    
    </LinearLayout>
    

    fragment_blue.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:orientation="vertical"
                  android:background="#30c9fb"
                  android:padding="16dp"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent">
    
        <TextView
            android:id="@+id/textview"
            android:text="TextView"
            android:textSize="24sp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    
    </LinearLayout>
    
    0 讨论(0)
提交回复
热议问题