This question already has answers here:
Communicating between a fragment and an activity - best practices
(11 answers)
Closed 4 years ago.
I need to pass data from activity to fragment. I know I can use bundle , but once I passed data,I can't send data without calling and creating fragment again.
In my activity, some thing may be changed and I need to notify my fragment for these changes without recreating fragment.
Create one interface in your Activity and pass your data via the interface to the fragment. Implement that interface in your fragment to get data.
For example
MainActivity.class
public class MainActivity extends AppCompatActivity {
DataFromActivityToFragment dataFromActivityToFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentA fr = new FragmentA();
FragmentManager fm = getFragmentManager();
dataFromActivityToFragment = (DataFromActivityToFragment) fr;
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.fragment_place, fr);
fragmentTransaction.commit();
final Handler handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
dataFromActivityToFragment.sendData("Hi");
}
};
handler.postDelayed(r, 5000);
}
public interface DataFromActivityToFragment {
void sendData(String data);
}
}
FragmentA.class
public class FragmentA extends Fragment implements MainActivity.DataFromActivityToFragment {
TextView text;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.content_main, null);
text = (TextView) rootView.findViewById(R.id.fragment_text);
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
public void sendData(String data) {
if(data != null)
text.setText(data);
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/fragment_place"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
</LinearLayout>
</LinearLayout>
content_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/fragment_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
In above example I have taken Runnable just to send data with delay of 5 seconds after creation of fragment.
Fragment object is just like other objects.Like String , you can invoke methods of string object, str.charAt(0) ,str.toUpperCase() etc. Just create a function in fragment, put your code there and call the function along with values
Inside Activity {
fragDemoObject.doWhatYouWant("this is passed as string object to fragment");
}
Inside FragmentDemo{
void doWhatYouWant(String input){
System.out.println(input);
// do what else you want to do with code
}
}
Actually your question is not related to:
I need to pass data from activity to fragmenet .I know I can use
bundle , but one i've passed data , I cant send anymore data without
calling and creating fragment once more .
The real one is this:
in my activity , some thing may be changed and I need to notify my
fragment from these changes without recreating fragment.
how can I do so ?
In this case I would store the fragment in the activity as reference and I would call a function, an interface implementation inside the fragment.
Something like this:
In Activity:
SomeEventListener myFragment ;
yourFragmentCreationMethod(){
if(myFragment == null){
myFragment = new MyFragment(maybeParamsHere);
}
}
yourNotificationMethod(){
myFragment .onEventHappent(param);
}
// declare an interface: - separate file
public interface SomeEventListener
{
void onEventHappent(param);
}
// implement the interface in Fragment - separate file
public class MyFragment extends Fragment implements SomeEventListener{
// add a constructor what you like
public void onEventHappent(param){
/// ... your update
}
}
The interface it will help you at testing only.
The host activity can deliver messages to a fragment by capturing the
Fragment instance with findFragmentById(), then directly call the
fragment's public methods.
In your fragment - MyFragment, create a public method
public void myFragmentDataFromActivity(int passedDataFromActivity) {
// do your stuff
}
In your activity to pass an integer value say, 100 :
get MyFragment instance using getSupportFragmentManager or getFragmentManager by providing id/tag/position. Then call the public method in MyFragment instance.
MyFragment myFragment = (MyFragment) getSupportFragmentManager.getFragmentById(id);
myFragment.myFragmentDataFromActivity(100);
You can also use getFragmentByTag(tag), getFragments().get(position) instead of getFragmentById(id) to get fragment instance.
read more about this
For notify fragment with some data after it's created, can be done using some Communicator, or you can always pass the data with bundle in creation time...
For example:
public interface FragmentCommunicator {
void updateDataToFragment(List<Parcelable> data);
}
then in your fragment implement this interface and calling it from the activity for example as:`
Fragment fragment = mSectionsPagerAdapter.getRegisteredFragment(i);
if (fragment instanceof FragmentCommunicator) {
FragmentCommunicator fragmentCommunicator = (FragmentCommunicator) fragment;
fragmentCommunicator.updateDataToFragment(data);
}`
This should works for your case...
try this one in Activity
fragment=new PdfFragment();
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
Bundle bundle = new Bundle();
bundle.putString("pdf", Pdf);
bundle.putString("flag", "0");
fragment.setArguments(bundle);
fragmentManager.beginTransaction().replace(R.id.container, fragment).addToBackStack(null).commit();
}
and in fragment
Pdf = getArguments().getString("pdf");
You should declare your method as public in the fragment to update new data. Then you will call that method via fragment instance. For example, write this in your activity when getting new data:
fragmentInstance.publicMethod(newData);
Happy coding!
I have also come across the same issue, I have used singleton class to
transfer data from activity to fragment (without making fragment
transaction or using inteface)
class DataPersistance {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPlace() {
return place;
}
public void setPlace(String place) {
this.place = place;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
private String name;
private String place;
private String type;
private static final DataPersistance ourInstance = new DataPersistance();
static DataPersistance getInstance() {
return ourInstance;
}
private DataPersistance() {
}
}
to set and get data
DataPersistance.getInstance().setName(mEditText.getText().toString());
String name = DataPersistance.getInstance().getName();
Related
With the following code I can click a button to send a string from one fragment (Fragment A) into a MainActivity. How would I retrieve the string from the MainActivity and display it on a fragment B all in one go? I would like the fragments to act synchronized; to have Fragment B update itself as soon as I click the button in Fragment A. I can't seem to find anything in SO on this.
Interface:
public interface OnDataListener {
public void onDataReceived(String data);
}
Fragment A data listener:
OnDataListener mOnDataListener;
#Override
public void onAttach(Context context) {
try{
mOnDataListener = (OnDataListener) context;
Log.d(TAG, "onAttach was called" + context);
}catch (ClassCastException e){
Log.e(TAG, "onAttach: ClassCastException: " + e.getMessage() );
}
super.onAttach(context);
}
Button logic in Fragment A's onCreateView:
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
String newTextString = editTextView.getText().toString();
mOnDataListener.onDataReceived(newTextString);
}
});
MainActivity data receiver
public class MainActivity extends AppCompatActivity implements OnDataListener {
#Override
public void onDataReceived(String data) {
Log.e(TAG, "MainActivity received this string " + data );
}
}
Solution 1: Using Callbacks
//this will work if your fragment instance is active so check viewpager offscreenpage limit
(You can also use solution 3 mentioned by Farid Haq, which do the same by doing work of activity itself)
Here, Activity implements callback OnDataUpdateListener
interface OnDataUpdateListener{
void passDataToFragmentB(String data)
}
Activity code:
Fragment instanceFragmentB;
// intialise it somewhere in your activity
// or get from viewpager adapter
#Override
void passDataToFragmentB(String data){
instanceFragmentB.onDataChange(data)
}
Fragment A code:
OnDataUpdateListener mOnDataUpdateListener;
onAttach(Activity activity){
mOnDataUpdateListener= (OnDataUpdateListener) activity
}
onViewCreated(){
somebutton.onClick{
mOnDataUpdateListener.passDataToFragmentB("someString")
}
}
Fragment B code:
onDataChange(String data){
//do your work with update data passed from fragment A
}
Solution 2: Using EventBus or RxBus
//this will work if your fragment instance is active so check viewpager offscreenpage limit
Using event or rxbus, post new updated value on bus and make destination fragment observing that same value type.
Fragment A:
onViewCreated(){
somebutton.onClick{
EventBus.post("your data")
}
}
Fragment B:
#Subsribe
void onDataChange(String data){
//do your work with update data passed from fragment A
}
Solution 3: Using ViewModel.
Take viewmodel with context of activity in all fragment and Wrap String with LiveData.
Whenever, string data is changed, just post new data on String Livedata object.
All fragment observing that livedata will get updated value.
Solution 1
In your MainActivity
#Override
public void onDataReceived(String data) {
Log.e(TAG, "MainActivity received this string " + data );
Bundle bundle = new Bundle();
bundle.putString("edttext", data);
FragmentB fragment = new FragmentB();
fragment.setArguments(bundle);
// Fragment Transaction method goes here
}
In your FragmentB Retrieve Data
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String strtext = getArguments().getString("edttext");
return inflater.inflate(R.layout.fragment, container, false);
}
Solution 2
You can put callback data to your global variable and use it at fragment transaction at the time of onClickListerner.
Solution 3
A) Create method in your FragmentB
public void changeText (String data) {
textview.setText(data)
}
B) And Pass Value From MainActivity
#Override
public void onDataReceived (String data) {
myInterface.CallBack("Callbacked when onCreate method Created" + data);
Log.d("Tiggered", "respond: ");
FragmentManager manager = getFragmentManager();
FragmentB fragmentB = (FragmentB) manager.findFragmentById(R.id.id_fragmentB);
fragmentB.changeText(data);
}
I am learning how to use fragments, and in my MainActivity.java I have this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
A a = new A();
B b = new B(a);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new ContentFragment())
.commit();
ContentFragment frag = (ContentFragment) getSupportFragmentManager()
.findFragmentById(R.id.container);
frag.doInject(b);
}
}
If I try to inject the dependency directly into the constructor of the fragment, Android Studio barks at me. So I'm trying this approach, but when debugging I get to where I am setting frag, and it's just null and is always null. So, I guess what I need to know is, in the simplest way possible, how do I call my doInject(b) and inject b into my fragment?
Another thing too, which I'm not sure about, is that later if I have a listener in the same MainActivity.java file, and I want to update the fragment with new content, I was hoping to do something like this:
#Override
public void handleResponseData(String s) {
frag.updateTextbox(s);
}
But I have a feeling that I'm going to run into problems with that too. So I need some help understanding what it is that I'm trying to do. I've spent at least 5 hours trying to figure this out, and need some help, please!
Edit to show layout files:
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:ignore="MergeRootFrame" />
fragment_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity">
<TextView
android:id="#+id/textbox"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Hello World" />
</FrameLayout>
If I try to inject the dependency directly into the constructor of the fragment
I'm not sure about that doInject method, but you should read Best practice for instantiating a new Android Fragment
For example,
ContentFragment frag = ContentFragment.newInstance(b);
getSupportFragmentManager().beginTransaction()
.add(R.id.container, frag, "TAG")
.commit();
// frag.doInject(b); // Can do, but not necessary
later if I have a listener in the same MainActivity.java file, and I want to update the fragment with new content, I was hoping to do something like this
Generally, this is not how you do that.
frag.updateTextbox(s);
I assume you have the Activity attached to the Fragment via a listener with a handleResponseData(String s), and you'd have to do
String s = "foo";
if (listener != null) {
listener.handleResponseData(s);
}
therefore, instead of that, you only need do this
String s = "foo";
updateTextbox(s);
/*
if (listener != null) {
listener.handleResponseData(s);
}
*/
instead of new ContentFragment() . create the fragment and give a tag for that.
Sample Example :
if (savedInstanceState == null) {
ContentFragment fragment = new ContentFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.container, fragment,"MyFragTag")
.commit();
ContentFragment frag = (ContentFragment) getSupportFragmentManager()
.findFragmentByTag("MyFragTag");
frag.doInject(b);
}
(This is the most common way to do it) Imagine this is your fragment :
public class FactoryMethodFragment extends Fragment {
public static final String ARG_MY_VALUE = "any value";
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Bundle arguments = getArguments();
String myValue = "empty";
if (arguments != null) {
myValue = arguments
.getString(ARG_MY_VALUE);
}
Toast.makeText(getContext(), myValue,
Toast.LENGTH_SHORT).show();
}
public static FactoryMethodFragment getInstance(String myValue){
FactoryMethodFragment factoryMethodFragment
= new FactoryMethodFragment();
Bundle arguments = new Bundle();
arguments.putString(ARG_MY_VALUE, myValue);
factoryMethodFragment.setArguments(arguments);
return factoryMethodFragment;
}
}
You have to create a factory method with arguments as shown in my example and use it like this :
getSupportFragmentManager().beginTransaction()
.add(R.id.container, FactoryMethodFragment.getInstance("myArgument"))
.commit();
And for the comunication between fragment and activity normally we use an interface as the following :
public class FactoryMethodFragment extends Fragment {
public static final String ARG_MY_VALUE = "any value";
public interface CommunicationChannel {
void onAction1(String argument);
void onAction2(String argument);
}
private CommunicationChannel mCallback;
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Bundle arguments = getArguments();
String myValue = "empty";
if (arguments != null) {
myValue = arguments
.getString(ARG_MY_VALUE);
}
Toast.makeText(getContext(), myValue,
Toast.LENGTH_SHORT).show();
//Here we will send data to the activity
mCallback.onAction1("data sent to activity");
mCallback.onAction2("Another data sent to activity");
}
public static FactoryMethodFragment getInstance(String myValue){
FactoryMethodFragment factoryMethodFragment
= new FactoryMethodFragment();
Bundle arguments = new Bundle();
arguments.putString(ARG_MY_VALUE, myValue);
factoryMethodFragment.setArguments(arguments);
return factoryMethodFragment;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof Activity) {
mCallback = (CommunicationChannel) context;
}
}
}
And you implement it on your activity like this :
public class FatoryMethodActivity extends AppCompatActivity implements FactoryMethodFragment.CommunicationChannel {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.id.yourlayout);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, FactoryMethodFragment.getInstance("myArgument"))
.commit();
}
}
#Override
public void onAction1(String argument) {
//HERE YOU GET DATA FROM YOUR FRAGMENT
}
#Override
public void onAction2(String argument) {
//HERE YOU GET DATA FROM YOUR FRAGMENT
}
}
Thanks to everyone here I stumbled my way through this issue, and even though I've probably got some mistakes, I thought I'd post what I've got in case it might help somebody else.
In MainActivity.java:
if (findViewById(R.id.fragment_container) != null) {
if (savedInstanceState == null) {
frag = ContentFragment.getInstance(request);
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, frag).commit();
}
}
In ContentFragment.java:
private PostRequest request;
private static ContentFragment myFragment = null;
public static ContentFragment getInstance(PostRequest request){
if( myFragment == null ){
myFragment = new ContentFragment();
myFragment.request = request;
}
return myFragment;
}
I've only been working with Android/Java for about 10 days, and for me it's a lot to take in. Anyways, thanks for the help!
I've Viewpager wit 2 fragments: CurrentWeatherFragment and ForecastFragment. I need to pass string from one to another, Iam using interface like below, but I keep getting NullPointerException, the message is not passing propertly...
public class CurrentWeatherFragment extends Fragment {
SendMessage SM
public void onCreateView(...) {
String Message = "Hello"
SM.sendData(Message);
}
interface SendMessage
{
public void sendData(String message);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
SM = (SendMessage) activity;
} catch(ClassCastException e) {
throw new ClassCastException("Musisz zaimplementowac metode sendData");
}
}
}
MainActivity.java
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.os.Bundle;
public class MainActivity extends FragmentActivity implements CurrentWeatherFragment.SendMessage {
ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//setting fragment view pager
viewPager = (ViewPager)findViewById(R.id.pager);
PagerAdapter pagerAdapter = new PagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
}
public void sendData (String message){
ForecastFragment FF = new ForecastFragment();
FF.getData(message);
}
}
ForecastFragment.java
public class ForecastFragment extends Fragment {
public View onCreateView(){
TextView txt = (TextView)v.findViewById(R.id.txt_forecast);
}
public void getData(String message){
txt.setText(message);
}
}
I've used this method succesfully in other app where I've had 2 fragments in one activity and i could call them by ID
public void sendData(String message) {
SecondFragment f2 = (SecondFragment)getFragmentManager().findFragmentById(R.id.F2);
f2.getData(message);
}
But here Fragments dont have IDs and I think that message is not passed because i dont use FragmentManager(), but how to find fragment in viewpager without ID, any suggestion/ideas?
Although a little hacky what you can do is get the fragment by its tag by using the following code:
String tag = "android:switcher:" + R.id.pager + ":" + index;
Fragment f = getSupportFragmentManager().findFragmentByTag(tag);
Where R.id.pager is the id of the viewpager in your layout and index is the position (as an integer) in the Viewpager Adapter.
I can't say this will work forever but it works for me at the moment.
The Alternative i would suggest is using a LocalBroadcastManager and a BroadcastReciver to send data internally between your fragments as although its a little more work it helps get rid of the spaghetti code situation you may end up finding yourself in trying to reference the fragments directly.
To pass data between fragments you need to pass the data in the object constructor.
Be aware to don't override the default constructor, instead create a static method getInstance(String data).
public static YourClass getInstance(String data)
{
YourClass object = new YourClass();
Bundle bundle = new Bundle();
bundle.putString(key, data);
object.setArguments(bundle);
return object;
}
Then you can get the data in the fragment's onCreate method with getArguments()
For some other users like me who looking for fragment to viewpager data sending
Here is working solution :
Sending data from fragment TO tab layout's view pager's fragments:
In Main fragment :
For tab layout i am using two fragments
1) BillDetailFragment and
2) ClientDepMonFragment
private TabLayout tabLayout;
private ViewPager viewPager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
view= inflater.inflate(R.layout.fragment_detail, container, false);
// adding fragment and passing data to it
BillDetailFragment billDetailFragment=new BillDetailFragment();
Bundle bundle=new Bundle();
bundle.putString("mobile",mobile);
bundle.putInt("c_id",client_id);
bundle.putInt("server_id",server_id);
billDetailFragment.setArguments(bundle);
ClientDepMonFragment clientDepMonFragment=new ClientDepMonFragment();
Bundle bundle1=new Bundle();
bundle1.putString("mobile",mobile);
bundle1.putInt("c_id",client_id);
bundle1.putInt("server_id",server_id);
clientDepMonFragment.setArguments(bundle1);
tabLayout=(TabLayout)view.findViewById(R.id.detail_txn_tab_layout);
viewPager=(ViewPager)view.findViewById(R.id.detail_txn_viewpager);
dtViewPagerAdapter=new DtViewPagerAdapter(getChildFragmentManager(),DetailFragment.this);
dtViewPagerAdapter.addFragments(billDetailFragment,"Lending Money");
dtViewPagerAdapter.addFragments(clientDepMonFragment,"Deposited Money");
viewPager.setAdapter(dtViewPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
}
and here is how to access that data from fragment
BillDetailFragment: override onCreate method
private int client_id,server_id;
private String client_mobile;
#Override
public void onCreate(#Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
client_mobile=getArguments().getString("mobile");
client_id=getArguments().getInt("c_id");
server_id=getArguments().getInt("server_id");
}
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 pass the String of text input by the user into Fragment A to the text view in Fragment B. However, this is proving to be very difficult. Does anyone know how I might achieve this?
I am aware that a fragment can get a reference to it's activity using getActivity(). So I'm guessing I would start there?
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
}
}
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>
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
Consider my 2 fragments A and B, and Suppose I need to pass data from B to A.
Then create an interface in B, and pass the data to the Main Activity. There create another interface and pass data to fragment A.
Sharing a small example:
Fragment A looks like
public class FragmentA extends Fragment implements InterfaceDataCommunicatorFromActivity {
public InterfaceDataCommunicatorFromActivity interfaceDataCommunicatorFromActivity;
String data;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void updateData(String data) {
// TODO Auto-generated method stub
this.data = data;
//data is updated here which is from fragment B
}
#Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
try {
interfaceDataCommunicatorFromActivity = (InterfaceDataCommunicatorFromActivity) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement TextClicked");
}
}
}
FragmentB looks like
class FragmentB extends Fragment {
public InterfaceDataCommunicator interfaceDataCommunicator;
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
// call this inorder to send Data to interface
interfaceDataCommunicator.updateData("data");
}
public interface InterfaceDataCommunicator {
public void updateData(String data);
}
#Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
try {
interfaceDataCommunicator = (InterfaceDataCommunicator) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement TextClicked");
}
}
}
Main Activity is
public class MainActivity extends Activity implements InterfaceDataCommunicator {
public InterfaceDataCommunicatorFromActivity interfaceDataCommunicatorFromActivity;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void updateData(String data) {
// TODO Auto-generated method stub
interfaceDataCommunicatorFromActivity.updateData(data);
}
public interface InterfaceDataCommunicatorFromActivity {
public void updateData(String data);
}
}
There are multiple ways to communicate between fragments.
Traditional way of communication via interface Example
Via ViewModel if you are following MVVM pattern Example
BroadcastReceivers: via LocalBraodcastManager Example or EventBus Example etc...
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/
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
Since Fragment 1.3.0 we have available a new way to communicate between fragments.
As of Fragment 1.3.0, each FragmentManager implements FragmentResultOwner.
That means that a FragmentManager can act as a central storage for fragment results. This change allows components to communicate with each other by setting chunk results and listening to those results without those components having direct references to each other.
Fragment listener:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Use the Kotlin extension in the fragment-ktx artifact
setFragmentResultListener("requestKey") { 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
}
}
Fragment emitter:
button.setOnClickListener {
val result = "result"
// Use the Kotlin extension in the fragment-ktx artifact
setFragmentResult("requestKey", bundleOf("bundleKey" to result))
}
Learn " setTargetFragment() "
Where " startActivityForResult() " establishes a relationship between 2 activities, " setTargetFragment() " defines the caller/called relationship between 2 fragments.
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;
}
}
You can user 2 approcach to communicate between 2 fragments:
1 )
You can use LiveData to observe data changes of one fragment in another
Create shared ViewModel
public class SharedViewModel extends ViewModel {
private MutableLiveData<String> name;
public void setNameData(String nameData) {
name.setValue(nameData);
}
public MutableLiveData<String> getNameData() {
if (name == null) {
name = new MutableLiveData<>();
}
return name;
}
}
Fragment One
private SharedViewModel sharedViewModel;
public FragmentOne() {
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sharedViewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
submitButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sharedViewModel.setNameData(submitText.getText().toString());
}
});
}
Fragment Two
private SharedViewModel sharedViewModel;
public FragmentTwo() {
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sharedViewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
sharedViewModel.getNameData().observe(this, nameObserver);
}
Observer<String> nameObserver = new Observer<String>() {
#Override
public void onChanged(String name) {
receivedText.setText(name);
}
};
For more details on viewmodel you can refer to : mvvm-viewmodel-livedata , communicate fragments
2 )
You can use eventbus to achieve the same
implementation 'org.greenrobot:eventbus:3.2'
Define Event
public static class MessageEvent { /* Additional fields if needed */ }
Register/Unregister Subsciber
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
Listen To Events
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
Post Events
EventBus.getDefault().post(new MessageEvent());
Basically, following are the ways for communication between two fragments:
i) ViewModel
ii) Fragment Result API
iii) Interface
I use many fragments on tabs that need to share data between them, such as a ble scan tab that needs up update a device id on a settings tab.
The communication is a mess for something simple like one edittext.
My solution was to save data to sharedpreferences and use the fragment onResume to read and update.
I can extend the fields in Sharedpreferences later if I need to as well.
Update
Ignore this answer. Not that it doesn't work. But there are better methods available. Moreover, Android emphatically discourage direct communication between fragments. See official doc. Thanks user #Wahib Ul Haq for the tip.
Original Answer
Well, you can create a private variable and setter in Fragment B, and set the value from Fragment A itself,
FragmentB.java
private String inputString;
....
....
public void setInputString(String string){
inputString = string;
}
FragmentA.java
//go to fragment B
FragmentB frag = new FragmentB();
frag.setInputString(YOUR_STRING);
//create your fragment transaction object, set animation etc
fragTrans.replace(ITS_ARGUMENTS)
Or you can use Activity as you suggested in question..
I recently created a library that uses annotations to generate those type casting boilerplate code for you.
https://github.com/zeroarst/callbackfragment
Here is an example. Click a TextView on DialogFragment triggers a callback to MainActivity in onTextClicked then grab the MyFagment instance to interact with.
public class MainActivity extends AppCompatActivity implements MyFragment.FragmentCallback, MyDialogFragment.DialogListener {
private static final String MY_FRAGM = "MY_FRAGMENT";
private static final String MY_DIALOG_FRAGM = "MY_DIALOG_FRAGMENT";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager().beginTransaction()
.add(R.id.lo_fragm_container, MyFragmentCallbackable.create(), MY_FRAGM)
.commit();
findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MyDialogFragmentCallbackable.create().show(getSupportFragmentManager(), MY_DIALOG_FRAGM);
}
});
}
Toast mToast;
#Override
public void onClickButton(MyFragment fragment) {
if (mToast != null)
mToast.cancel();
mToast = Toast.makeText(this, "Callback from " + fragment.getTag() + " to " + this.getClass().getSimpleName(), Toast.LENGTH_SHORT);
mToast.show();
}
#Override
public void onTextClicked(MyDialogFragment fragment) {
MyFragment myFragm = (MyFragment) getSupportFragmentManager().findFragmentByTag(MY_FRAGM);
if (myFragm != null) {
myFragm.updateText("Callback from " + fragment.getTag() + " to " + myFragm.getTag());
}
}
}
Im trying to pass data between two fragmens in my program. Its just a simple string that is stored in the List. The List is made public in fragments A, and when the user clicks on a list item, I need it to show up in fragment B. The content provider only seems to support ID's, so that will not work. Any suggestions?
Why don't you use a Bundle. From your first fragment, here's how to set it up:
Fragment fragment = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt(key, value);
fragment.setArguments(bundle);
Then in your second Fragment, retrieve the data using:
Bundle bundle = this.getArguments();
int myInt = bundle.getInt(key, defaultValue);
Bundle has put methods for lots of data types. Please see http://developer.android.com/reference/android/os/Bundle.html
If you use Roboguice you can use the EventManager in Roboguice to pass data around without using the Activity as an interface. This is quite clean IMO.
If you're not using Roboguice you can use Otto too as a event bus: http://square.github.com/otto/
Update 20150909: You can also use Green Robot Event Bus or even RxJava now too. Depends on your use case.
From the Fragment documentation:
Often you will want one Fragment to communicate with another, for example to change the content based on a user event. All Fragment-to-Fragment communication is done through the associated Activity. Two Fragments should never communicate directly.
So I suggest you have look on the basic fragment training docs in the documentation. They're pretty comprehensive with an example and a walk-through guide.
So lets say you have Activity AB that controls Frag A and Fragment B.
Inside Fragment A you need an interface that Activity AB can implement.
In the sample android code, they have:
private Callbacks mCallbacks = sDummyCallbacks;
/*A callback interface that all activities containing this fragment must implement. This mechanism allows activities to be notified of item selections.
*/
public interface Callbacks {
/*Callback for when an item has been selected. */
public void onItemSelected(String id);
}
/*A dummy implementation of the {#link Callbacks} interface that does nothing. Used only when this fragment is not attached to an activity. */
private static Callbacks sDummyCallbacks = new Callbacks() {
#Override
public void onItemSelected(String id) {
}
};
The Callback interface is put inside one of your Fragments (let’s say Fragment A). I think the purpose of this Callbacks interface is like a nested class inside Frag A which any Activity can implement. So if Fragment A was a TV, the CallBacks is the TV Remote (interface) that allows Fragment A to be used by Activity AB. I may be wrong about the detail because I'm a noob but I did get my program to work perfectly on all screen sizes and this is what I used.
So inside Fragment A, we have:
(I took this from Android’s Sample programs)
#Override
public void onListItemClick(ListView listView, View view, int position, long id) {
super.onListItemClick(listView, view, position, id);
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mCallbacks.onItemSelected(DummyContent.ITEMS.get(position).id);
//mCallbacks.onItemSelected( PUT YOUR SHIT HERE. int, String, etc.);
//mCallbacks.onItemSelected (Object);
}
And inside Activity AB we override the onItemSelected method:
public class AB extends FragmentActivity implements ItemListFragment.Callbacks {
//...
#Override
//public void onItemSelected (CATCH YOUR SHIT HERE) {
//public void onItemSelected (Object obj) {
public void onItemSelected(String id) {
//Pass Data to Fragment B. For example:
Bundle arguments = new Bundle();
arguments.putString(“FragmentB_package”, id);
FragmentB fragment = new FragmentB();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction().replace(R.id.item_detail_container, fragment).commit();
}
So inside Activity AB, you basically throwing everything into a Bundle and passing it to B. If u are not sure how to use a Bundle, look the class up.
I am basically going by the sample code that Android provided. The one with the DummyContent stuff. When you make a new Android Application Package, it's the one titled MasterDetailFlow.
1- The first way is define an interface
public interface OnMessage{
void sendMessage(int fragmentId, String message);
}
public interface OnReceive{
void onReceive(String message);
}
2- In you activity implement OnMessage interface
public class MyActivity implements OnMessage {
...
#Override
public void sendMessage(int fragmentId, String message){
Fragment fragment = getSupportFragmentManager().findFragmentById(fragmentId);
((OnReceive) fragment).sendMessage();
}
}
3- In your fragment implement OnReceive interface
public class MyFragment implements OnReceive{
...
#Override
public void onReceive(String message){
myTextView.setText("Received message:" + message);
}
}
This is the boilerplate version of handling message passing between fragments.
Another way of handing data passage between fragments are by using an event bus.
1- Register/unregister to an event bus
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
2- Define an event class
public class Message{
public final String message;
public Message(String message){
this.message = message;
}
}
3- Post this event in anywhere in your application
EventBus.getDefault().post(new Message("hello world"));
4- Subscribe to that event to receive it in your Fragment
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(Message event){
mytextview.setText(event.message);
}
For more details, use cases, and an example project about the event bus pattern.
IN my case i had to send the data backwards from FragmentB->FragmentA hence Intents was not an option as the fragment would already be initialised All though all of the above answers sounds good it takes a lot of boiler plate code to implement, so i went with a much simpler approach of using LocalBroadcastManager, it exactly does the above said but without alll the nasty boilerplate code. An example is shared below.
In Sending Fragment(Fragment B)
public class FragmentB {
private void sendMessage() {
Intent intent = new Intent("custom-event-name");
intent.putExtra("message", "your message");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
And in the Message to be Received Fragment(FRAGMENT A)
public class FragmentA {
#Override
public void onCreate(Bundle savedInstanceState) {
...
// Register receiver
LocalBroadcastManager.getInstance(this).registerReceiver(receiver,
new IntentFilter("custom-event-name"));
}
// This will be called whenever an Intent with an action named "custom-event-name" is broadcasted.
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("message");
}
};
}
Hope it helps someone
That depends on how the fragment is structured. If you can have some of the methods on the Fragment Class B static and also the target TextView object static, you can call the method directly on Fragment Class A. This is better than a listener as the method is performed instantaneously, and we don't need to have an additional task that performs listening throughout the activity. See example below:
Fragment_class_B.setmyText(String yourstring);
On Fragment B you can have the method defined as:
public static void setmyText(final String string) {
myTextView.setText(string);
}
Just don't forget to have myTextView set as static on Fragment B, and properly import the Fragment B class on Fragment A.
Just did the procedure on my project recently and it worked. Hope that helped.
you can read this doc .this concept is well explained here http://developer.android.com/training/basics/fragments/communicating.html
I'm working on a similar project and I guess my code may help in the above situation
Here is the overview of what i'm doing
My project Has two fragments Called "FragmentA" and "FragmentB"
-FragmentA Contains one list View,when you click an item in FragmentA It's INDEX is passed to FragmentB using Communicator interface
The design pattern is totally based on the concept of java interfaces that says
"interface reference variables can refer to a subclass object"
Let MainActivity implement the interface provided by fragmentA(otherwise we can't make interface reference variable to point to MainActivity)
In the below code communicator object is made to refer to MainActivity's object by using "setCommunicator(Communicatot c)" method present in fragmentA.
I'm triggering respond() method of interface from FrgamentA using the MainActivity's reference.
Interface communcator is defined inside fragmentA, this is to provide least access previlage to communicator interface.
below is my complete working code
FragmentA.java
public class FragmentA extends Fragment implements OnItemClickListener {
ListView list;
Communicator communicater;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
return inflater.inflate(R.layout.fragmenta, container,false);
}
public void setCommunicator(Communicator c){
communicater=c;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
communicater=(Communicator) getActivity();
list = (ListView) getActivity().findViewById(R.id.lvModularListView);
ArrayAdapter<?> adapter = ArrayAdapter.createFromResource(getActivity(),
R.array.items, android.R.layout.simple_list_item_1);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int index, long arg3) {
communicater.respond(index);
}
public interface Communicator{
public void respond(int index);
}
}
fragmentB.java
public class FragmentA extends Fragment implements OnItemClickListener {
ListView list;
Communicator communicater;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
return inflater.inflate(R.layout.fragmenta, container,false);
}
public void setCommunicator(Communicator c){
communicater=c;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
communicater=(Communicator) getActivity();
list = (ListView) getActivity().findViewById(R.id.lvModularListView);
ArrayAdapter<?> adapter = ArrayAdapter.createFromResource(getActivity(),
R.array.items, android.R.layout.simple_list_item_1);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int index, long arg3) {
communicater.respond(index);
}
public interface Communicator{
public void respond(int index);
}
}
MainActivity.java
public class MainActivity extends Activity implements FragmentA.Communicator {
FragmentManager manager=getFragmentManager();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentA fragA=(FragmentA) manager.findFragmentById(R.id.fragmenta);
fragA.setCommunicator(this);
}
#Override
public void respond(int i) {
// TODO Auto-generated method stub
FragmentB FragB=(FragmentB) manager.findFragmentById(R.id.fragmentb);
FragB.changetext(i);
}
}
Basically Implement the interface to communicate between Activity and fragment.
1) Main activty
public class MainActivity extends Activity implements SendFragment.StartCommunication
{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public void setComm(String msg) {
// TODO Auto-generated method stub
DisplayFragment mDisplayFragment = (DisplayFragment)getFragmentManager().findFragmentById(R.id.fragment2);
if(mDisplayFragment != null && mDisplayFragment.isInLayout())
{
mDisplayFragment.setText(msg);
}
else
{
Toast.makeText(this, "Error Sending Message", Toast.LENGTH_SHORT).show();
}
}
}
2) sender fragment (fragment-to-Activity)
public class SendFragment extends Fragment
{
StartCommunication mStartCommunicationListner;
String msg = "hi";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View mView = (View) inflater.inflate(R.layout.send_fragment, container);
final EditText mEditText = (EditText)mView.findViewById(R.id.editText1);
Button mButton = (Button) mView.findViewById(R.id.button1);
mButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
msg = mEditText.getText().toString();
sendMessage();
}
});
return mView;
}
interface StartCommunication
{
public void setComm(String msg);
}
#Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
if(activity instanceof StartCommunication)
{
mStartCommunicationListner = (StartCommunication)activity;
}
else
throw new ClassCastException();
}
public void sendMessage()
{
mStartCommunicationListner.setComm(msg);
}
}
3) receiver fragment (Activity-to-fragment)
public class DisplayFragment extends Fragment
{
View mView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
mView = (View) inflater.inflate(R.layout.display_frgmt_layout, container);
return mView;
}
void setText(String msg)
{
TextView mTextView = (TextView) mView.findViewById(R.id.textView1);
mTextView.setText(msg);
}
}
I used this link for the same solution, I hope somebody will find it usefull.
Very simple and basic example.
http://infobloggall.com/2014/06/22/communication-between-activity-and-fragments/
getParentFragmentManager().setFragmentResultListener is the 2020 way of doing this. Your only limitation is to use a bundle to pass the data. Check out the docs for more info and examples.
Some other ways
Call to getActivity() and cast it to the shared activity between your fragments, then use it as a bridge to pass the data. This solution is highly not recommended because of the cupelling it requires between the activity and the fragments, but it used to be the popular way of doing this back in the KitKat days...
Use callbacks. Any events mechanism will do. This would be a Java vanilla solution. The benefit over FragmentManager is that it's not limited to Bundles. The downside, however, is that you may run into edge cases bugs where you mess up the activity life cycle and get exceptions like IllegalStateException when the fragment manager is in the middle of saving state or the activity were destroyed. Also, it does not support cross-processing communication.
Fragment class A
public class CountryListFragment extends ListFragment{
/** List of countries to be displayed in the ListFragment */
ListFragmentItemClickListener ifaceItemClickListener;
/** An interface for defining the callback method */
public interface ListFragmentItemClickListener {
/** This method will be invoked when an item in the ListFragment is clicked */
void onListFragmentItemClick(int position);
}
/** A callback function, executed when this fragment is attached to an activity */
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try{
/** This statement ensures that the hosting activity implements ListFragmentItemClickListener */
ifaceItemClickListener = (ListFragmentItemClickListener) activity;
}catch(Exception e){
Toast.makeText(activity.getBaseContext(), "Exception",Toast.LENGTH_SHORT).show();
}
}
Fragment Class B
public class CountryDetailsFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
/** Inflating the layout country_details_fragment_layout to the view object v */
View v = inflater.inflate(R.layout.country_details_fragment_layout, null);
/** Getting the textview object of the layout to set the details */
TextView tv = (TextView) v.findViewById(R.id.country_details);
/** Getting the bundle object passed from MainActivity ( in Landscape mode ) or from
* CountryDetailsActivity ( in Portrait Mode )
* */
Bundle b = getArguments();
/** Getting the clicked item's position and setting corresponding details in the textview of the detailed fragment */
tv.setText("Details of " + Country.name[b.getInt("position")]);
return v;
}
}
Main Activity class for passing data between fragments
public class MainActivity extends Activity implements ListFragmentItemClickListener {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
/** This method will be executed when the user clicks on an item in the listview */
#Override
public void onListFragmentItemClick(int position) {
/** Getting the orientation ( Landscape or Portrait ) of the screen */
int orientation = getResources().getConfiguration().orientation;
/** Landscape Mode */
if(orientation == Configuration.ORIENTATION_LANDSCAPE ){
/** Getting the fragment manager for fragment related operations */
FragmentManager fragmentManager = getFragmentManager();
/** Getting the fragmenttransaction object, which can be used to add, remove or replace a fragment */
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
/** Getting the existing detailed fragment object, if it already exists.
* The fragment object is retrieved by its tag name *
*/
Fragment prevFrag = fragmentManager.findFragmentByTag("in.wptrafficanalyzer.country.details");
/** Remove the existing detailed fragment object if it exists */
if(prevFrag!=null)
fragmentTransaction.remove(prevFrag);
/** Instantiating the fragment CountryDetailsFragment */
CountryDetailsFragment fragment = new CountryDetailsFragment();
/** Creating a bundle object to pass the data(the clicked item's position) from the activity to the fragment */
Bundle b = new Bundle();
/** Setting the data to the bundle object */
b.putInt("position", position);
/** Setting the bundle object to the fragment */
fragment.setArguments(b);
/** Adding the fragment to the fragment transaction */
fragmentTransaction.add(R.id.detail_fragment_container, fragment,"in.wptrafficanalyzer.country.details");
/** Adding this transaction to backstack */
fragmentTransaction.addToBackStack(null);
/** Making this transaction in effect */
fragmentTransaction.commit();
}else{ /** Portrait Mode or Square mode */
/** Creating an intent object to start the CountryDetailsActivity */
Intent intent = new Intent("in.wptrafficanalyzer.CountryDetailsActivity");
/** Setting data ( the clicked item's position ) to this intent */
intent.putExtra("position", position);
/** Starting the activity by passing the implicit intent */
startActivity(intent);
}
}
}
Detailde acitivity class
public class CountryDetailsActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/** Setting the layout for this activity */
setContentView(R.layout.country_details_activity_layout);
/** Getting the fragment manager for fragment related operations */
FragmentManager fragmentManager = getFragmentManager();
/** Getting the fragmenttransaction object, which can be used to add, remove or replace a fragment */
FragmentTransaction fragmentTransacton = fragmentManager.beginTransaction();
/** Instantiating the fragment CountryDetailsFragment */
CountryDetailsFragment detailsFragment = new CountryDetailsFragment();
/** Creating a bundle object to pass the data(the clicked item's position) from the activity to the fragment */
Bundle b = new Bundle();
/** Setting the data to the bundle object from the Intent*/
b.putInt("position", getIntent().getIntExtra("position", 0));
/** Setting the bundle object to the fragment */
detailsFragment.setArguments(b);
/** Adding the fragment to the fragment transaction */
fragmentTransacton.add(R.id.country_details_fragment_container, detailsFragment);
/** Making this transaction in effect */
fragmentTransacton.commit();
}
}
Array Of Contries
public class Country {
/** Array of countries used to display in CountryListFragment */
static String name[] = new String[] {
"India",
"Pakistan",
"Sri Lanka",
"China",
"Bangladesh",
"Nepal",
"Afghanistan",
"North Korea",
"South Korea",
"Japan",
"Bhutan"
};
}
For More Details visit this link [http://wptrafficanalyzer.in/blog/itemclick-handler-for-listfragment-in-android/]. There are full example ..
Basically here we are dealing with communication between Fragments. Communication between fragments can never be directly possible. It involves activity under the context of which both the fragments are created.
You need to create an interface in the sending fragment and implement the interface in the activity which will reprieve the message and transfer to the receiving fragment.