Passing data between a fragment and its container activity

AndroidAndroid Fragments

Android Problem Overview


How can I pass data between a fragment and its container activity? Is there something similar to passing data between activities through intents?

I read this, but it didn't help much:
http://developer.android.com/guide/topics/fundamentals/fragments.html#CommunicatingWithActivity

Android Solutions


Solution 1 - Android

Try using interfaces.

Any fragment that should pass data back to its containing activity should declare an interface to handle and pass the data. Then make sure your containing activity implements those interfaces. For example:

JAVA

In your fragment, declare the interface...

public interface OnDataPass {
    public void onDataPass(String data);
}

Then, connect the containing class' implementation of the interface to the fragment in the onAttach method, like so:

OnDataPass dataPasser;

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    dataPasser = (OnDataPass) context;
}

Within your fragment, when you need to handle the passing of data, just call it on the dataPasser object:

public void passData(String data) {
    dataPasser.onDataPass(data);
}

Finally, in your containing activity which implements OnDataPass...

@Override
public void onDataPass(String data) {
    Log.d("LOG","hello " + data);
}

KOTLIN

Step 1. Create Interface

interface OnDataPass {
    fun onDataPass(data: String)
}

Step 2. Then, connect the containing class' implementation of the interface to the fragment in the onAttach method (YourFragment), like so:

lateinit var dataPasser: OnDataPass

override fun onAttach(context: Context) {
    super.onAttach(context)
    dataPasser = context as OnDataPass
}

Step 3. Within your fragment, when you need to handle the passing of data, just call it on the dataPasser object:

fun passData(data: String){
    dataPasser.onDataPass(data)
}

Step 4. Finally, in your activity implements OnDataPass

class MyActivity : AppCompatActivity(), OnDataPass {}

override fun onDataPass(data: String) {
    Log.d("LOG","hello " + data)
}

Solution 2 - Android

In your fragment you can call getActivity().

This will give you access to the activity that created the fragment. From there you can obviously call any sort of accessor methods that are in the activity.

e.g. for a method called getResult() on your Activity:

((MyActivity) getActivity()).getResult();

Solution 3 - Android

Easiest Approach but not Recommended

You can access activity data from fragment:

Activity:

public class MyActivity extends Activity {

    private String myString = "hello";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        ...
    }

    public String getMyData() {
        return myString;
    }
}

Fragment:

public class MyFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        MyActivity activity = (MyActivity) getActivity();
        String myDataFromActivity = activity.getMyData();
        return view;
    }
}

Solution 4 - Android

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
		Bundle savedInstanceState) {
	Bundle b = getActivity().getIntent().getExtras();
            wid = b.getString("wid");
            rid = b.getString("rid");
            View view = inflater.inflate(R.layout.categoryfragment, container, false);
	return view;
 }

Solution 5 - Android

Passing data between a fragment and its container activity

Activity:

		Bundle bundle = new Bundle();
		bundle.putString("message", "Alo Elena!");
		FragmentClass fragInfo = new FragmentClass();
		fragInfo.setArguments(bundle);
		transaction.replace(R.id.fragment_single, fragInfo);
		transaction.commit();

Fragment:

Reading the value in the fragment

    	@Override
    	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        String myValue = this.getArguments().getString("message");
        ...
        ...
        ...
        }

Solution 6 - Android

I don't know if this is the best way or not Bu I have been searching on google for quite a while finding how can I pass a Bundle from a fragment to its container activity but all I found was sending data from activity to fragment instead (which was a bit confusing for me as I'm a newbie).

later I tried something own my own that exactly worked for me as I wanted. so I'll post it here case someone like me looking for the same thing.

// Passing data from Fragment .

Bundle gameData = new Bundle();
		gameData.putStringArrayList(Constant.KEY_PLAYERS_ARR,players);
		gameData.putString(Constant.KEY_TEAM_NAME,custom_team_name);
		gameData.putInt(Constant.KEY_REQUESTED_OVER,requestedOver);
		
		Intent intent = getActivity().getIntent();
		intent.putExtras(gameData);

// Getting data from the bundle from it's container activity .

Bundle gameData = getIntent().getExtras();
		if (gameData != null)
		{
			int over = gameData.getInt(Constant.KEY_REQUESTED_OVER);
			ArrayList<String> players = gameData.getStringArrayList(Constant.KEY_PLAYERS_ARR);
			String team = gameData.getString(Constant.KEY_TEAM_NAME);

		}
		else if (gameData == null)
		{
			Toast.makeText(this, "Bundle is null", Toast.LENGTH_SHORT).show();
		}

Solution 7 - Android

Interface is one of the best solutions:

Glue Interface:

public interface DataProviderFromActivity {

	public String getName();
	public String getId);

}  

MyActivity:

public class MyActivity implements DataProviderFromActivity{
	
	String name = "Makarov";
	String id = "sys533";

	... ... ... ... ... .... .... 
	... ... ... ... ... .... .... 

	public String getName(){
		return name;
	};
	public String getId(){
		return id;
	};
}

MyFragment:

public class MyFragment extends Fragment{
	
	String fragName = "";
	String fragId = "";
	
	... ... ... ... ... .... .... 
	... ... ... ... ... .... .... 
	
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        DataProviderFromActivity myActivity= (DataProviderFromActivity) getActivity();
        fragName = myActivity.getName();
        fragId = myActivity.getId();
		
		... ... ... ... ... .... .... 
		... ... ... ... ... .... .... 

        updateFragmentView();
    }
}

Solution 8 - Android

I used an AppCompatActivity that implements Date Listeners. Fragments came as a necessity since I needed to code a date range selector. And I also needed the container to receive the selected dates to return them to the parent activity.

For the container activity, this is the class declaration:

public class AppCompatDateRange extends AppCompatActivity implements
    DateIniRangeFragment.OnDateIniSelectedListener, DateFimRangeFragment.OnDateFimSelectedListener

And the interfaces for the callbacks:

@Override
public void onDateIniSelected(String dataIni) {
    Log.i("data inicial:", dataIni);
}

@Override
public void onDateFimSelected(String dataFim) {
    Log.i("data final:", dataFim);
}

The callbacks are strings because dates are params in an query select.

The code for the fragments (based on the initial date fragment):

public class DateIniRangeFragment extends Fragment {
OnDateIniSelectedListener callbackIni;

private DatePicker startDatePicker;

public DateIniRangeFragment() {
    ///required empty constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

///through this interface the fragment sends data to the container activity
public interface OnDateIniSelectedListener {
    void onDateIniSelected(String dataIni);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    ///layout for the fragment
    View v = inflater.inflate(R.layout.date_ini_fragment, container, false);

    ///initial date for the picker, in this case, current date
    startDatePicker = (DatePicker) v.findViewById(R.id.start_date_picker_appcompat);
    Calendar c = Calendar.getInstance();
    int ano = c.get(Calendar.YEAR);
    int mes = c.get(Calendar.MONTH);
    int dia = c.get(Calendar.DAY_OF_MONTH);
    startDatePicker.setSpinnersShown(false);
    startDatePicker.init(ano, mes, dia, dateSetListener);

    return v;
}

///listener that receives the selected date
private DatePicker.OnDateChangedListener dateSetListener = new DatePicker.OnDateChangedListener() {
    public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
        if (view.isShown()) { ///if the datepicker is on the screen
            String sDataIni = year + "-" + (monthOfYear + 1) + "-" + dayOfMonth;
            callbackIni.onDateIniSelected(sDataIni); //apply date to callback, string format
        }
    }
};

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    /*
    * this function guarantees that the container activity implemented the callback interface
    * */
    try {
        callbackIni = (OnDateIniSelectedListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString() + " deve implementar OnDateIniSelectedListener");
    }
}

}

To compose the container + fragments, I used an ViewPager (AppCompat) with a custom class that extends FragmentPagerAdapter. No dialogs.

Solution 9 - Android

Simply you can use EventBus it is easy and work great

EventBus in 3 steps

  1. Define events:

public static class MessageEvent { /* Additional fields if needed */ }

  1. Prepare subscribers: Declare and annotate your subscribing method, optionally specify a thread mode:

    @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) {/* Do something */};

Register and unregister your subscriber. For example on Android, activities and fragments should usually register according to their life cycle:

 @Override
 public void onStart() {
     super.onStart();
     EventBus.getDefault().register(this);
 }

 @Override
 public void onStop() {
     super.onStop();
     EventBus.getDefault().unregister(this);
 }
  1. Post events:

    EventBus.getDefault().post(new MessageEvent());

Solution 10 - Android

I know this might be late. But I was also always lost on this question. Im sharing this link... because this is possibly the best explanation I ever found on the web for this. This solves Fragment to Activity & Fragment to Fragment!

Solved & Explained really well

Solution 11 - Android

This is working for me..

in Activity add this method

    public void GetData(String data)
     {
        // do something with your data        
     }

and in Fragment add this line

((YourActivity)getContext).GetData("your data here");

Solution 12 - Android

public class Fragmentdemo extends Fragment {

  public interface onDemoEventListener {
    public void demoEvent(String s);
  }

  onDemoEventListener demoEventListener;

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
        try {
          demoEventListener = (onDemoEventListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement onDemoEventListener");
        }
  }

  final String LOG_TAG = "TAG";

  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragmentdemo, null);

    Button button = (Button) v.findViewById(R.id.button);
    button.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        demoEventListener.someEvent("Test text to Fragment1");
      }
    });
    enter code here
    return v;
  }
}

Solution 13 - Android

First create interface in your Fragment.java

 public interface SendDataInterface{
     public void sendData(String data);
 }

Then create a reference of Activity in Fragment.java by overriding onAttach(Context context) method

@Override
public void onAttach(@NonNull Context context) {
    super.onAttach(context);
    Activity activity =(Activity)context ;
    try{
        mSendDataInterface= (SendDataInterface) activity;
    }catch(RuntimeException e){
        throw new RuntimeException(activity.toString()+" must implement method");
    }
}

Your Fragment.java should look like this :

public class FirstFragment extends Fragment {

private Button mButton;
private EditText mEditText;
SendDataInterface mSendDataInterface;

public FirstFragment(){ }

/**
 * We can not directly access the data of Fragment
 * So we should create an interface
 *
 */
 public interface SendDataInterface{
     public void sendData(String data);
 }


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view =  inflater.inflate(R.layout.fragment_first, container, false);
    mButton = view.findViewById(R.id.button);
    mEditText = view.findViewById(R.id.editText);

    mButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String data= mEditText.getText().toString();
            mSendDataInterface.sendData(data);
        }
    });
    return view;
}

/**
 * We create a reference of activity
 */
@Override
public void onAttach(@NonNull Context context) {
    super.onAttach(context);
    Activity activity =(Activity)context ;
    try{
        mSendDataInterface= (SendDataInterface) activity;
    }catch(RuntimeException e){
        throw new RuntimeException(activity.toString()+" must implement method");
    }
}

Implement SendDataInterface interface in your MainActivity.java

public class MainActivity extends AppCompatActivity implements FirstFragment.SendDataInterface {

private TextView mTextView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mTextView = findViewById(R.id.textView);

    if(findViewById(R.id.container) != null){

        // Check if app is on Resume in Lifecycle
        if(savedInstanceState != null){
            return;
        }

        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
                .add(R.id.container,new FirstFragment(),null)
                .commit();
    }
}

@Override
public void sendData(String data) {
    mTextView.setText(data);
}
}

Done

Solution 14 - Android

From the google official guide:

Starting with Fragment 1.3.0-alpha04, each FragmentManager implements FragmentResultOwner. This means that a FragmentManager can act as a central store for fragment results. This change allows components to communicate with each other by setting fragment results and listening for those results without requiring those components to have direct references to each other.

In Fragment: The child fragment sets the result on its FragmentManager. The parent then receives the result once the fragment is STARTED:

button.setOnClickListener {
    val result = "result"
    // Use the Kotlin extension in the fragment-ktx artifact
    setFragmentResult("requestKey", bundleOf("bundleKey" to result))
}

In the host Activity: To receive a fragment result in the host activity, set a result listener on the fragment manager using getSupportFragmentManager().

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        supportFragmentManager
                .setFragmentResultListener("requestKey", this) { requestKey, bundle ->
            // We use a String here, but any type that can be put in a Bundle is supported
            val result = bundle.getString("bundleKey")
            // Do something with the result
        }
    }
}

Solution 15 - Android

One effective solution I used to convert data from a fragment to an activity is:

In fragment:

Intent intent = new Intent(this, OtherActivity.class);
Bundle bundle = new Bundle();
bundle.putString("KEY", Value);
intent.putExtras(bundle);
getActivity().startActivity(bundle);

//------------------------------------------------------------

In Activity get data:

Bundle bundle = getIntent().getExtras();
if (bundle != null){
String getData = bundle.getString("KEY");
}

Done!

Solution 16 - Android

Another simple way to get datas, passed from another activity, in a fragment in a container activity : for example :

> Activity_A => Activity_B(Fragment)

In your Activity_A you create an intent like you're sending a data (String here) to another activity :

Intent intent = new Intent(getBaseContext(),Activity_B.class);
intent.putExtra("NAME", "Value");
startActivity(intent);

in your Fragment, contained in your Activity_B :

String data = getActivity().getIntent().getExtras();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiontybView Question on Stackoverflow
Solution 1 - AndroidHarlo HolmesView Answer on Stackoverflow
Solution 2 - AndroidNickView Answer on Stackoverflow
Solution 3 - AndroidZar E AhmerView Answer on Stackoverflow
Solution 4 - AndroidJeetuView Answer on Stackoverflow
Solution 5 - AndroidJorgesysView Answer on Stackoverflow
Solution 6 - AndroidFrozen DiaryView Answer on Stackoverflow
Solution 7 - AndroidHASSAN MD TAREQView Answer on Stackoverflow
Solution 8 - AndroidPabloView Answer on Stackoverflow
Solution 9 - AndroidSattarView Answer on Stackoverflow
Solution 10 - AndroidYo AppsView Answer on Stackoverflow
Solution 11 - AndroidBasantView Answer on Stackoverflow
Solution 12 - AndroidShweta ChandaranaView Answer on Stackoverflow
Solution 13 - AndroidUndenCemView Answer on Stackoverflow
Solution 14 - AndroidAllenView Answer on Stackoverflow
Solution 15 - AndroidAnthonyCodeView Answer on Stackoverflow
Solution 16 - AndroidSuperZouzouView Answer on Stackoverflow