Florian Walther
Florian Walther

Reputation: 6971

Android: Communication between an Activity and a Fragment

I am beginner, trying to learn while doing, and the Google results are too complicated for me at this point.

I have an Activity and successfully managed to make a fragment open and close via button press.

public void pressedButton(View v) {
    FragmentActivity fragmentActivity = new FragmentActivity();

    FragmentManager fragmentManager = getSupportFragmentManager();
    android.support.v4.app.FragmentTransaction ft = fragmentManager.beginTransaction();

    ft.add(R.id.frame_which_takes_the_fragment, FragmentActivity, "FRAGMENT_TAG");
    ft.commit();

As the fragment class stipulates, i implemented its "OnFragmentInteractionListener" interface in the Activity and overrode the onFragmentInteraction method.

@Override
public void onFragmentInteraction(Uri uri) {

}

And now I don't know how to progress. How do i send a variable from the activity to the fragment (for example to update a number in the user interface) and how do I send information back?

Please, keep in mind that I am a bloody beginner and try to keep it as basic and simple as possible.

Thanks in advance.

Upvotes: 2

Views: 7780

Answers (5)

Waheed Nazir
Waheed Nazir

Reputation: 614

ViewModels approach:

Fragments can share a ViewModel using their activity scope to handle this communication, as illustrated by the following sample code: This is clearly explained in Google's official doc. https://developer.android.com/topic/libraries/architecture/viewmodel#sharing

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.
        });
    }
}
enter code here

Another very good blog to study this: 8 ways to communicate between Fragment and Activity in Android apps. https://hackernoon.com/8-ways-to-communicate-between-fragment-and-activity-in-android-apps-235b60005d04

Upvotes: 1

Abhishek Kumar
Abhishek Kumar

Reputation: 4808

There are many ways of the communication between two fragments of the same activity.

  1. Easiest way is by using Static keywords. Here we can define methods and variables as static that we wanna share with other fragment and other fragment can directly access these variables. But biggest problem with this approach is that it leads to memory leak(coz of static definition).
  2. Another way is by using Interfaces. Here, we use method of an Interface in one fragment to pass the values and then we implement this interface in our parent activity and override the method there, then we use that method to pass the value to the child fragment.
  3. Another and most efficient way is by using ViewModel. As we know that ViewModel retains until the entire scope it was created for. So generally we use this keyword to bind ViewModel to the View as mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);. So if we use this keyword, the scope for the ViewModel remains until the fragment is destroyed only, once the fragment is destroyed, the ViewModel is cleared as well. So if we use getActivity() as a scope for the ViewModel then ViewModel will remain until the Activity is destroyed. Now suppose, you have a ViewModelA for A fragment, and you want to pass some value to the B fragment from A, now what you can do is, you can bind B fragment to ViewModelB as well as ViewModelA and hence you can observe for any change in certain value of ViewModelA in fragment B.

Upvotes: 0

Boycott A.I.
Boycott A.I.

Reputation: 18881

How do i send a variable from the activity to the fragment (for example to update a number in the user interface)?

I tried to do this by getting the ListFragment from my adapter and calling the fragment method, but I got this error:

IllegalStateException: Can't access ViewModels from detached fragment

My solution was to use LocalBroadcastManager instead:

Activity code

LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
Intent broadcastIntent = new Intent("MAP_SETTINGS_CHANGED");
broadcastIntent.putExtra("NUMBER_TO_SHOW_IN_FRAGMENT", 11);
localBroadcastManager.sendBroadcast(broadcastIntent);

ListFragment/Fragment code

private Context mContext;
private BroadcastReceiver mBroadcastReceiver;

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    mContext = context;

    mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, Intent intent) {

            String action = intent.getAction();
            if ("MAP_SETTINGS_CHANGED".equals(action)) {
                int numberToShow = intent.getIntExtra("NUMBER_TO_SHOW_IN_FRAGMENT", -1);
                showNumber(numberToShow);
            }
        }
    };

    LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(mContext);
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("MAP_SETTINGS_CHANGED");
    localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);

}

@Override
public void onDetach() {
    super.onDetach();

    LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(mContext);
    localBroadcastManager.unregisterReceiver(mBroadcastReceiver);

    mContext = null;
}

Upvotes: 0

Shalauddin Ahamad Shuza
Shalauddin Ahamad Shuza

Reputation: 3657

As ViewModel is released you can use shared ViewModelto communicate between fragments and activity. You just need to create ViewModel in activity scope and the ViewModel will be shared with activity and all child fragment.

SharedViewModel sharedViewModel = ViewModelProviders.of(getActivity()).get(SharedViewModel::class.java);

Then just observe the data

sharedViewModel.inputNumber.observe(this, observer);  // observer is your observer object

Upvotes: 3

Ridcully
Ridcully

Reputation: 23655

So, you already created an interface in the fragment and implemented it in the activity? Then you just have to create the interface following your needs. The onFragmentInteraction(Uri uri) method is just an example, which you can remove, if you don't want to pass an Uri from the fragment to activity.

So, to pass a number, your interface could look like this:

interface Listener {
    void onNumberChanged(int number);
}

The relevant fragment code:

listener.onNumberChanged(someNumber);

The relevant activity code:

@Override
public void onNumberChanged(int number) {
    someTextView.setText(Integer.toString(number));
}

Upvotes: 3

Related Questions