Currently trying to use a bundle to transfer information from both my IncomeFragment and ExpenseFragment to HomeFragment but I'm unsure as to how to do it. I've tried implementing doubleA's code which he provided.
This is my onAcceptClicked method from my MainActivity which takes the value of the total income/expense from the relevant fragment and transfers it to the HomeFragment:
public void onAcceptClicked(String fragment, String total) {
final FragmentManager fm = getFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
if (fragment == "income") {
HomeFragment homeFrag = new HomeFragment();
Bundle incomeBundle = new Bundle();
incomeBundle.putString(IncomeFragment.TAG, total);
//homeFrag.newInstance(total);
ft.replace(R.id.content_layout, homeFrag, HomeFragment.TAG);
ft.commit();
}
else if (fragment == "expense"){
HomeFragment homeFragment = new HomeFragment();
Bundle expenseBundle = new Bundle();
expenseBundle.putString("bundleIncome", total);
homeFragment.setArguments(expenseBundle);
ft.replace(R.id.content_layout, homeFragment, HomeFragment.TAG);
ft.commit();
}
}
I have an interface in my IncomeFragment which I use to communicate with my MainActivity so I can use the onAcceptClicked method to transfer my totals over. I plan on basically doing the same thing with my ExpenseFragment. The code below is a snippet from my IncomeFragment:
public interface SendIncomeData {
public void onAcceptClicked(String fragment, String total);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_accept:
//Toast.makeText(getActivity(), stringIncomeTotal, Toast.LENGTH_LONG).show();
sendIncomeData.onAcceptClicked("income", stringIncomeTotal);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Unfortunately I'm getting an error with this line of code
sendIncomeData.onAcceptClicked("income", stringIncomeTotal);
This is the error
java.lang.NullPointerException: Attempt to invoke interface method 'void mos.myapplication.IncomeFragment$SendIncomeData.onAcceptClicked(java.lang.String, java.lang.String)' on a null object reference
I don't know why it's saying there's a null object reference and/or how I could fix this error.
I'm guessing there's probably going to be an error displaying my totals in my HomeFragment because I haven't called the method below anywhere within my code in my MainActivity or my IncomeFragment / ExpenseFragment. The reason I haven't used it is because I wasn't sure how to get it so that the HomeFragment opens first when the application is launched.
static HomeFragment newInstance(String total)
{
HomeFragment frag = new HomeFragment();
Bundle args = new Bundle();
args.putString(TAG, total);
frag.setArguments(args);
return frag;
}
I don't even mind starting from scratch, as long as I can transfer totals and display them from IncomeFragment > HomeFragment and also ExpenseFragment > HomeFragment
You need to check if bundle is null in the first place:
bundle = this.getArguments();
if (bundle != null)
{
// continue with your logic
}
Also, all Fragment-to-Fragment communication is done through the associated Activity. Two Fragments should never communicate directly. See below links for more info:
http://developer.android.com/training/basics/fragments/communicating.html
http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity
A lot of people will argue that using interfaces is the best way to do that, which isn't really wrong but there are much simpler ways. Edit: not necessarily simpler
-One way is to get a reference to the activity within the fragment by calling
this.getActivity();
then in your activity class you can have a method that passes the data to the other fragment since it has a reference to both fragments.
-Then there's an even better way to do it actually (though that first part is probably helpful too):
In the fragment that has the data that needs to be moved, you can get a reference to the other fragment from the FragmentManager. This assumes that you created that fragment with a string ID like so:
Fragment otherFragment;
getSupportFragmentManager().beginTransaction().add(otherFragment, "otherFrag").commit();
Then in the fragment with the data, you'll do:
FragmentActivity fragmentActivity = (FragmentActivity)getActivity();
OtherFragment otherFragment = (OtherFragment)fragmentActivity.getSupportFragmentManager().findFragmentByTag("otherFrag");
Then with a reference to OtherFragment (in this case), you can do something like:
otherFragment.dataString = "myData";
But you'll probably want to have a test to make sure the other fragment doesn't come back null, and if it is null you might just want to create it then and there since you already have a reference to the FragmentManager.
Edit: I'm just going to say that I like this method more, subjectively.
I have a Class1 extending ListFragment1.
I have a Class2 extending ListFragment2.
I'm currently passing an Intent like this inside OnItemClickListener.
Intent intent = new Intent(getActivity().getApplicationContext(), ListFragment2.class);
intent.putExtra("id", "1");
getActivity().startActivity(intent);
}
However, i get this exception:
java.lang.ClassCastException: com.abc.xyz.Class2 cannot be cast to android.app.Activity
Please help ! :(
First you should know:
You are calling startActivity(intent) and your Intent is pointing to a Fragment.
You cannot pass intents to your Fragment like that since Fragments are not App Components.
Communcation between Fragments should be between the Activity holding them.
Best Solution:
Pass your data from Class1 to your Activity and then send it to Class2, this link provides you exactly this, no more or less code:
http://developer.android.com/training/basics/fragments/communicating.html
It's a must read when you want to communicate between fragments.
Intent must point towards a class extending android.app.Activity which is not a case with your code.
Instead of extending ListFragment2 externally, you can make an inner class extending ListFragment2 and pass the value.
Hope this helps.
Both the fragments must communicate with the activity for communication between each other.The activity acts as a sort of a mediater between the fragement.The flow will look like this:
Fragment1 passes the intent to Activity1 with certain parameters which helps Activity1 to identify that it needs to pass this intent to Fragment2.
Activity1 on receiving the intent, passes this intent to Fragment 2.
How the fragment communicates with activity can be designed in following way mentioned here
To allow a Fragment to communicate up to its Activity, you can define an interface in the Fragment class and implement it within the Activity. The Fragment captures the interface implementation during its onAttach() lifecycle method and can then call the Interface methods in order to communicate with the Activity.
public class HeadlinesFragment extends ListFragment {
OnHeadlineSelectedListener mCallback;
// Container Activity must implement this interface
public interface OnHeadlineSelectedListener {
public void onArticleSelected(int position);
}
#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 = (OnHeadlineSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
...
}
Now the fragment can deliver messages to the activity by calling the onArticleSelected() method (or other methods in the interface) using the mCallback instance of the OnHeadlineSelectedListener interface.
For example, the following method in the fragment is called when the user clicks on a list item. The fragment uses the callback interface to deliver the event to the parent activity.
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Send the event to the host activity
mCallback.onArticleSelected(position);
}
Implement the Interface
In order to receive event callbacks from the fragment, the activity that hosts it must implement the interface defined in the fragment class.
For example, the following activity implements the interface from the above example.
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
}
}
Deliver a Message to a Fragment
The host activity can deliver messages to a fragment by capturing the Fragment instance with findFragmentById(), then directly call the fragment's public methods.
For instance, imagine that the activity shown above may contain another fragment that's used to display the item specified by the data returned in the above callback method. In this case, the activity can pass the information received in the callback method to the other fragment that will display the item:
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Do something here to display that article
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
if (articleFrag != null) {
// If article frag is available, we're in two-pane layout...
// Call a method in the ArticleFragment to update its content
articleFrag.updateArticleView(position);
} else {
// Otherwise, we're in the one-pane layout and must swap frags...
// Create fragment and give it an argument for the selected article
ArticleFragment newFragment = new ArticleFragment();
Bundle args = new Bundle();
args.putInt(ArticleFragment.ARG_POSITION, position);
newFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
}
This is one of the way to achieve it, i use constructor to pass the data
FragmentOne.java
int myData=12;
FragmentManager manager = getActivity().getSupportFragmentManager();
Fragment frgObj=FragmentTwo.newInstance(myData);
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.container, frgObj,"FragmentTwo");
ft.addToBackStack(null);
ft.commit();
FragmentTwo.java
int myData;
public static FragmentTwo newInstance(int _myData){
FragmentTwo fragment = new FragmentTwo();
myData=_myData
return fragment;
}
ALSO REFER -- this -- StackOVERFLOW POST
Hello my Android application is using fragments. I am wondering if there is a way I can use the idea of the onBackPressed() method in my app with fragments. I have previous and next buttons, but as of now I am just creating new fragments and replacing, and none of the data gets saved. Is there a way to save my data/go back once I have gone forward?
The concept of Fragment is different of Activity.
One Activity could have a many Fragments, read that:
A Fragment represents a behavior or a portion of user interface in an
Activity. You can combine multiple fragments in a single activity to
build a multi-pane UI and reuse a fragment in multiple activities. You
can think of a fragment as a modular section of an activity, which has
its own lifecycle, receives its own input events, and which you can
add or remove while the activity is running (sort of like a "sub
activity" that you can reuse in different activities).
See more here: http://developer.android.com/guide/components/fragments.html
SOLUCTION
So if you wanna handle the onBackPressed behavior in you Fragment you could do that:
package com.example.stackoverflowsandbox;
import android.app.Activity;
import android.app.Fragment;
public class MainActivity extends Activity {
public class MyFragment extends Fragment {
public void onBackPressed() {
// your code here...
}
}
private MyFragment myFragment;
#Override
public void onBackPressed() {
// super.onBackPressed(); // comment to not back
this.myFragment.onBackPressed(); // the onBackPressed method of Fragment is a custom method
}
}
Sorry, do not know if I understand your question, but if the idea and have control of direct backbutton in its fragment, and from it to perform some task of data persistence, you can add your fragment to control stack FragmentManager, the as follows.
FragmentManager fm = getSupportFragmentManager();
MyFragment mMyFragment = new MyFragment();
fm.beginTransaction()
.add(mMyFragment, "mMyFragment")
.addToBackStack( null )
.commit();
In the fragment you need to implement the interface OnBackStackChangedListener
In Fragment:
public class MyFragment extends Fragment implements OnBackStackChangedListener {
#Override
public void onBackStackChanged() {
//your code here
}
}
If you just keep the values
public class MyFragment extends Fragment {
String valeu;
#Override
public void onCreate( final Bundle savedInstanceState ) {
super.onCreate( savedInstanceState );
if ( savedInstanceState != null ) {
this.valeu = savedInstanceState.getString( "key" );
}
}
#Override
public void onSaveInstanceState( final Bundle outState ) {
super.onSaveInstanceState( outState );
outState.putString( "key", "Your content" );
}
}
while moving to front fragment, save the state of previous fragment using onSaveInstanceState()
while moving back restore the state in onCreate() or onCreateView() in the previous fragment
I have two classes. First is activity, second is a fragment where I have some EditText. In activity I have a subclass with async-task and in method doInBackground I get some result, which I save to variable. How can I send this variable from subclass "my activity" to this fragment?
From Activity you send data with intent as:
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
// set Fragmentclass Arguments
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);
and in Fragment onCreateView method:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String strtext = getArguments().getString("edttext");
return inflater.inflate(R.layout.fragment, container, false);
}
Also 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;
}
}
I´ve found a lot of answers here # stackoverflow.com but definitely this is the correct answer of:
"Sending data from activity to fragment in android".
Activity:
Bundle bundle = new Bundle();
String myMessage = "Stackoverflow is cool!";
bundle.putString("message", myMessage );
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) {
Bundle bundle = this.getArguments();
String myValue = bundle.getString("message");
...
...
...
}
or just
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
String myValue = this.getArguments().getString("message");
...
...
...
}
This answer may be too late. but it will be useful for future readers.
I have some criteria. I have coded for pick the file from intent. and selected file to be passed to particular fragment for further process. i have many fragments having the functionality of File picking. at the time , every time checking the condition and get the fragment and pass the value is quite disgusting. so , i have decided to pass the value using interface.
Step 1: Create the interface on Main Activity.
public interface SelectedBundle {
void onBundleSelect(Bundle bundle);
}
Step 2: Create the SelectedBundle reference on the Same Activity
SelectedBundle selectedBundle;
Step 3: create the Method in the Same Activity
public void setOnBundleSelected(SelectedBundle selectedBundle) {
this.selectedBundle = selectedBundle;
}
Step 4: Need to initialise the SelectedBundle reference which are all fragment need filepicker functionality.You place this code on your fragment onCreateView(..) method
((MainActivity)getActivity()).setOnBundleSelected(new MainActivity.SelectedBundle() {
#Override
public void onBundleSelect(Bundle bundle) {
updateList(bundle);
}
});
Step 5: My case, i need to pass the image Uri from HomeActivity to fragment. So, i used this functionality on onActivityResult method.
onActivityResult from the MainActivity, pass the values to the fragments using interface.
Note: Your case may be different. you can call it from any where from your HomeActivity.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
selectedBundle.onBundleSelect(bundle);
}
Thats all. Implement every fragment you needed on the FragmentClass. You are great. you have done. WOW...
The best and convenient approach is calling fragment instance and send data at that time.
every fragment by default have instance method
For example :
if your fragment name is MyFragment
so you will call your fragment from activity like this :
getSupportFragmentManager().beginTransaction().add(R.id.container, MyFragment.newInstance("data1","data2"),"MyFragment").commit();
*R.id.container is a id of my FrameLayout
so in MyFragment.newInstance("data1","data2") you can send data to fragment and in your fragment you get this data in MyFragment newInstance(String param1, String param2)
public static MyFragment newInstance(String param1, String param2) {
MyFragment fragment = new MyFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
and then in onCreate method of fragment you'll get the data:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
so now mParam1 have data1 and mParam2 have data2
now you can use this mParam1 and mParam2 in your fragment.
Basic Idea of using Fragments (F) is to create reusable self sustaining UI components in android applications. These Fragments are contained in activities and there are common(best) way of creating communication path ways from A -> F and F-A, It is a must to Communicate between F-F through a Activity because then only the Fragments become decoupled and self sustaining.
So passing data from A -> F is going to be the same as explained by ρяσѕρєя K. In addition to that answer, After creation of the Fragments inside an Activity, we can also pass data to the fragments calling methods in Fragments.
For example:
ArticleFragment articleFrag = (ArticleFragment)
getSupportFragmentManager().findFragmentById(R.id.article_fragment);
articleFrag.updateArticleView(position);
I would like to add for the beginners that the difference between the 2 most upvoted answers here is given by the different use of a fragment.
If you use the fragment within the java class where you have the data you want to pass, you can apply the first answer to pass data:
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);
If however you use for example the default code given by Android Studio for tabbed fragments, this code will not work.
It will not work even if you replace the default PlaceholderFragment with your FragmentClasses, and even if you correct the FragmentPagerAdapter to the new situation adding a switch for getItem() and another switch for getPageTitle() (as shown here)
Warning: the clip mentioned above has code errors, which I explain later here, but is useful to see how you go from default code to editable code for tabbed fragments)! The rest of my answer makes much more sense if you consider the java classes and xml files from that clip (representative for a first use of tabbed fragments by a beginner scenario).
The main reason the most upvoted answer from this page will not work is that in that default code for tabbed fragments, the fragments are used in another java class: FragmentPagerAdapter!
So, in order to send the data, you are tempted to create a bundle in the MotherActivity and pass it in the FragmentPagerAdapter, using answer no.2.
Only that is wrong again. (Probably you could do it like that, but it is just a complication which is not really needed).
The correct/easier way to do it, I think, is to pass the data directly to the fragment in question, using answer no.2.
Yes, there will be tight coupling between the Activity and the Fragment, BUT, for tabbed fragments, that is kind of expected. I would even advice you to create the tabbed fragments inside the MotherActivity java class (as subclasses, as they will never be used outside the MotherActivity) - it is easy, just add inside the MotherActivity java class as many Fragments as you need like this:
public static class Tab1 extends Fragment {
public Tab1() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.your_layout_name_for_fragment_1, container, false);
return rootView;
}
}.
So, to pass data from the MotherActivity to such a Fragment you will need to create private Strings/Bundles above the onCreate of your Mother activity - which you can fill with the data you want to pass to the fragments, and pass them on via a method created after the onCreate (here called getMyData()).
public class MotherActivity extends Activity {
private String out;
private Bundle results;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mother_activity);
// for example get a value from the previous activity
Intent intent = getIntent();
out = intent.getExtras().getString("Key");
}
public Bundle getMyData() {
Bundle hm = new Bundle();
hm.putString("val1",out);
return hm;
}
}
And then in the fragment class, you use getMyData:
public static class Tab1 extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
public Tab1() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.your_layout_name_for_fragment_1, container, false);
TextView output = (TextView)rootView.findViewById(R.id.your_id_for_a_text_view_within_the_layout);
MotherActivity activity = (MotherActivity)getActivity();
Bundle results = activity.getMyData();
String value1 = results.getString("val1");
output.setText(value1);
return rootView;
}
}
If you have database queries I advice you to do them in the MotherActivity (and pass their results as Strings/Integers attached to keys inside a bundle as shown above), as inside the tabbed fragments, your syntax will become more complex (this becomes getActivity() for example, and getIntent becomes getActivity().getIntent), but you have also the option to do as you wish.
My advice for beginners is to focus on small steps. First, get your intent to open a very simple tabbed activity, without passing ANY data. Does it work? Does it open the tabs you expect? If not, why?
Start from that, and by applying solutions such as those presented in this clip, see what is missing. For that particular clip, the mainactivity.xml is never shown. That will surely confuse you. But if you pay attention, you will see that for example the context (tools:context) is wrong in the xml fragment files. Each fragment XML needs to point to the correct fragment class (or subclass using the separator $).
You will also see that in the main activity java class you need to add tabLayout.setupWithViewPager(mViewPager) - right after the line TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs); without this line, your view is actually not linked to the XML files of the fragments, but it shows ONLY the xml file of the main activity.
In addition to the line in the main activity java class, in the main activity XML file you need to change the tabs to fit your situation (e.g. add or remove TabItems). If you do not have tabs in the main activity XML, then possibly you did not choose the correct activity type when you created it in the first place (new activity - tabbed activity).
Please note that in the last 3 paragraphs I talk about the video! So when I say main activity XML, it is the main activity XML in the video, which in your situation is the MotherActivity XML file.
If you pass a reference to the (concrete subclass of) fragment into the async task, you can then access the fragment directly.
Some ways of passing the fragment reference into the async task:
If your async task is a fully fledged class (class FooTask extends AsyncTask), then pass your fragment into the constructor.
If your async task is an inner class, just declare a final Fragment variable in the scope the async task is defined, or as a field of the outer class. You'll be able to access that from the inner class.
From Activity you send data with Bundle as:
Bundle bundle = new Bundle();
bundle.putString("data", "Data you want to send");
// Your fragment
MyFragment obj = new MyFragment();
obj.setArguments(bundle);
And in Fragment onCreateView method get the data:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
String data = getArguments().getString("data");// data which sent from activity
return inflater.inflate(R.layout.myfragment, container, false);
}
Sometimes you can receive Intent in your activity and you need to pass the info to your working fragment.
Given answers are OK if you need to start the fragment but if it's still working, setArguments() is not very useful.
Another problem occurs if the passed information will cause to interact with your UI. In that case you cannot call something like myfragment.passData() because android will quickly tells that only the thread which created the view can interact with.
So my proposal is to use a receiver. That way, you can send data from anywhere, including the activity, but the job will be done within the fragment's context.
In you fragment's onCreate():
protected DataReceiver dataReceiver;
public static final String REC_DATA = "REC_DATA";
#Override
public void onCreate(Bundle savedInstanceState) {
data Receiver = new DataReceiver();
intentFilter = new IntentFilter(REC_DATA);
getActivity().registerReceiver(dataReceiver, intentFilter);
}
private class DataReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int data= intent.getIntExtra("data", -1);
// Do anything including interact with your UI
}
}
In you activity:
// somewhere
Intent retIntent = new Intent(RE_DATA);
retIntent.putExtra("data", myData);
sendBroadcast(retIntent);
Very old post, still I dare to add a little explanation that would had been helpful for me.
Technically you can directly set members of any type in a fragment from activity.
So why Bundle?
The reason is very simple - Bundle provides uniform way to handle:-- creating/opening fragment
-- reconfiguration (screen rotation) - just add initial/updated bundle to outState in onSaveInstanceState()
-- app restoration after being garbage collected in background (as with reconfiguration).
You can (if you like experiments) create a workaround in simple situations but Bundle-approach just doesn't see difference between one fragment and one thousand on a backstack - it stays simple and straightforward. That's why the answer by #Elenasys is the most elegant and universal solution. And that's why the answer given by #Martin has pitfalls
If an activity needs to make a fragment perform an action after initialization, the easiest way is by having the activity invoke a method on the fragment instance. In the fragment, add a method:
public class DemoFragment extends Fragment {
public void doSomething(String param) {
// do something in fragment
}
}
and then in the activity, get access to the fragment using the fragment manager and call the method:
public class MainActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DemoFragment fragmentDemo = (DemoFragment)
getSupportFragmentManager().findFragmentById(R.id.fragmentDemo);
fragmentDemo.doSomething("some param");
}
}
and then the activity can communicate directly with the fragment by invoking this method.
the better approach for sending data from activity class to fragment is passing via setter methods. Like
FragmentClass fragmentClass = new FragmentClass();
fragmentClass.setMyList(mylist);
fragmentClass.setMyString(myString);
fragmentClass.setMyMap(myMap);
and get these data from the class easily.
Use following interface to communicate between activity and fragment
public interface BundleListener {
void update(Bundle bundle);
Bundle getBundle();
}
Or use following this generic listener for two way communication using interface
/**
* Created by Qamar4P on 10/11/2017.
*/
public interface GenericConnector<T,E> {
T getData();
void updateData(E data);
void connect(GenericConnector<T,E> connector);
}
fragment show method
public static void show(AppCompatActivity activity) {
CustomValueDialogFragment dialog = new CustomValueDialogFragment();
dialog.connector = (GenericConnector) activity;
dialog.show(activity.getSupportFragmentManager(),"CustomValueDialogFragment");
}
you can cast your context to GenericConnector in onAttach(Context) too
in your activity
CustomValueDialogFragment.show(this);
in your fragment
...
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
connector.connect(new GenericConnector() {
#Override
public Object getData() {
return null;
}
#Override
public void updateData(Object data) {
}
#Override
public void connect(GenericConnector connector) {
}
});
}
...
public static void show(AppCompatActivity activity, GenericConnector connector) {
CustomValueDialogFragment dialog = new CustomValueDialogFragment();
dialog.connector = connector;
dialog.show(activity.getSupportFragmentManager(),"CustomValueDialogFragment");
}
Note: Never use it like "".toString().toString().toString(); way.
just stumbled across this question, while most of the methods above will work.
I just want to add that you can use the Event Bus Library, especially in scenarios where the component (Activity or Fragment) has not been created, its good for all sizes of android projects and many use cases. I have personally used it in several projects i have on playstore.
You can create public static method in fragment where you will get static reference of that fragment and then pass data to that function and set that data to argument in same method and get data via getArgument on oncreate method of fragment, and set that data to local variables.
I ran into a similar issue while using the latest Navigation architecture component. Tried out all the above-mentioned code with passing a bundle from my calling activity to Fragment.
The best solution, following the latest development trends in Android, is by using View Model (part of Android Jetpack).
Create and Initialize a ViewModel class in the parent Activity, Please note that this ViewModel has to be shared between the activity and fragment.
Now, Inside the onViewCreated() of the fragment, Initialize the Same ViewModel and setup Observers to listen to the ViewModel fields.
Here is a helpful, in-depth tutorial if you need.
https://medium.com/mindorks/how-to-communicate-between-fragments-and-activity-using-viewmodel-ca733233a51c
Kotlin version:
In Activity:
val bundle = Bundle()
bundle.putBoolean("YourKey1", true)
bundle.putString("YourKey2", "YourString")
val fragment = YourFragment()
fragment.arguments = bundle
val fragmentTransaction = parentFragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.your_container, fragment, fragment.toString())
fragmentTransaction.commit()
In the Fragment onCreate():
var value1 = arguments?.getBoolean("YourKey1", default true/false)
var value2 = arguments?.getString("YourKey2", "Default String")
Smartest tried and tested way of passing data between fragments and activity is to create a variables,example:
class StorageUtil {
public static ArrayList<Employee> employees;
}
Then to pass data from fragment to activity, we do so in the onActivityCreated method:
//a field created in the sending fragment
ArrayList<Employee> employees;
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
employees=new ArrayList();
//java 7 and above syntax for arraylist else use employees=new ArrayList<Employee>() for java 6 and below
//Adding first employee
Employee employee=new Employee("1","Andrew","Sam","1984-04-10","Male","Ghanaian");
employees.add(employee);
//Adding second employee
Employee employee=new Employee("1","Akuah","Morrison","1984-02-04","Female","Ghanaian");
employees.add(employee);
StorageUtil.employees=employees;
}
Now you can get the value of StorageUtil.employees from everywhere.
Goodluck!
My solution is to write a static method inside the fragment:
public TheFragment setData(TheData data) {
TheFragment tf = new TheFragment();
tf.data = data;
return tf;
}
This way I am sure that all the data I need is inside the Fragment before any other possible operation which could need to work with it.
Also it looks cleaner in my opinion.
You can make a setter method in the fragment. Then in the Activity, when you reference to the fragment, you call the setter method and pass it the data from you Activity
In your activity declare static variable
public static HashMap<String,ContactsModal> contactItems=new HashMap<String, ContactsModal>();
Then in your fragment do like follow
ActivityName.contactItems.put(Number,contactsModal);