Hi i am new to Fragments i searched many pages but still i didn't get correct answer for my questions. I want to know how data transfer while implementing Fragments. I have three cases
1. Fragment to Fragment data transfer : By implementing a Callback Interface
2. Fragment to Activity data transfer : By using getActivity().
3. Activity to Fragment data transfer : My problem was occurred here. I referred many sites but nobody given clear explanation.Please help me.
For transfer data at the time of creation of the fragment, do this:
Fragment newFragment = MyFragment.newInstance(any argument);
In constructor of fragment, do this:
public static MyFragment newInstance(int someInt) {
MyFragment myFragment = new MyFragment();
Bundle args = new Bundle();
args.putInt("someInt", someInt);
myFragment.setArguments(args);
return myFragment;
}
Then for instantiate a fragment now, you make call newInstance() instead of new Fragment(). For recover the data of a fragment on fragment, do this:
int myData = getArguments().getInt("someInt", 0);
For transfer data from activity to fragment in a time of execution implementing a Callback Interface too.
If what you want is to have a reference in your activity to the fragment,
then make your fragment register in your activity using an interface:
public interface RegisterFragment {
public void setFragmentReference(MyFragment frag);
}
implement the interface in your activity, which defines a method to save a fragment reference:
public class MainActivity extends FragmentActivity implements RegisterFragment {
private MyFragment myFragmentReference;
public void setFragmentReference(MyFragment frag) {
this.myFragmentReference = frag;
}
public void usingFragmentReference() {
if(myFragmentReference != null)
myFragmentReference.doSomething("string data");
}
}
In your fragment subclass, save the reference using the interface method:
public class MyFragment extends Fragment {
#Override
public void onStart() {
RegisterFragment rf = (RegisterFragment)getActivity();
rf.setFragmentReference(this);
}
public void doSomething(String data) {
...
}
}
This way your activity can communicate with your fragment when required.
Related
I was working on communication between multiple fragments in a activity stack.
I have figured out 2 ways to do this.
Through interfaces
Through Bundle setarguments
Bundle bundle = new Bundle();
bundle.putBoolean("Status",trur);
Fragment fragment = getFragmentManager().findFragmentByTag(bottomfragment.class.getName());
if(fragment!=null) {
fragment.setArguments(bundle);
}
I felt the 2nd approach easy.Since Google recommends 1 st approach
Can anyone help me with the problems I may face by following 2nd approach.
You are mixing the both the ways.
1. through interfaces is if you want to communicate from fragment to activity or fragment to fragment(via activity)
2. set argument is if you want to pass arguments while starting the fragment. you can call methods of fragment using the instance you get from fragment id/tag
Please referfragment communication
Try to communication between two fragments like this:
1) Create Interface like this:
public interface FragmentChangeListener {
void changeFragment(Fragment fragment);
}
2) Update MainActivity like this:
public class MainActivity extends AppCompatActivity implements FragmentChangeListener
{
//Activity code
------
#Override
public void changeFragment(Fragment fragment) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction tr = fm.beginTransaction();
tr.replace(R.id.frame_container, fragment);
tr.commitAllowingStateLoss();
}
}
3) Create First Fragment:
public class FirstFragment extends Fragment
{
// call another freagment like this
//in your oncreateview method:
SecondFragment
Bundle b = new Bundle();
b.putSerializable(SELECTED_ITEM, true);
SecondFragment second = SecondFragment.newInstance(b);
FragmentChangeListener fc = (FragmentChangeListener) getActivity();
fc.changeFragment(second);
}
4) Second Fragment:
public class SecondFragment extends Fragment
{
public static SecondFragment newInstance(Bundle bundle) {
SecondFragment fragment = new SecondFragment();
if (bundle != null)
fragment.setArguments(bundle);
return fragment;
}
//another fragment related code
//In your OncreateView like this:
if (getArguments() != null)
boolean temp = getArguments().getBoolean(IntentParameter.SELECTED_ITEM);
}
Hope this explanation help you :)
Argument (Bundle) should be passed to Fragment only initially (when Fragment's object is created by default constructor). Calling setArguments method on already added Fragment will cause IllegalStateException. See body of setArguments method:
public void setArguments(Bundle args) {
if (mIndex >= 0 && isStateSaved()) {
throw new IllegalStateException("Fragment already active and state has been saved");
}
mArguments = args;
}
If you want to change something in Fragment A from Fragment B :
a) Get an object of A inside B using
getFragmentManager().findFragmentByTag("FRAGMENT_A_TAG");
Or
getFragmentManager().findFragmentById(FRAGMENT_A_CONTAINER_ID);
Cast returned object to A and call proper method on it. (It's the simplest way, but after it, A and B become highly coupled);
b) Alternatively, you can write mentioned logic inside method of Activity, which contains these 2 Fragments, get reference of this Activity inside B using getContext() casted to container Activity and call mentioned method on it (It kills reusability, because if you want to have A and B on other Activity, casting getContext() will cause ClassCastException);
c) The best way, to communicate between Fragments is to create interface, implement container Activity by this interface, get reference of this interface inside B and call proper method on it. (You can implement as many activities as you want by this interface, so it's reusable approach and A and B are loosely coupled).
I'm a newbie in android developer. I have a question about transfer with 3 fragments.
I have 3 fragments (A - B - C). I want o transfer data from A -> B -> C.
In each the fragment, data was been changed.
When user click BACK BUTTON, user want to return A with the updated data.
How to return fragment A with the update data?
Thanks.
Here is a sample idea how to achieve communication.
// activity classs
public class SampleActivity extends Activity implements OnFragmentChangeListener {
OnBackPressListener dataFragment;
public void onCreate(bundle){
android.app.FragmentManager fragmentManager=getFragmentManager();
android.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
dataFragment = new DataFragment();
fragmentTransaction.add(R.id.audio_permission_button,dataFragment);
fragmentTransaction.commit()
}
#override
public void OnFragmentChange(Bundle bundle){
//here you go.
// write code to load new fragment with same idea. now you have bundle do what you want.
}
#Override
public void onBackPressed() {
// you can call this method from any click event, This just an sample idea.
dataFragment.OnActivityBackPress();
}
}
// interface to communicate with fragment
public interface OnFragmentChangeListener {
public void OnFragmentChange()
}
// fragment class
public class DataFragment extends Fragment implements OnBackPressListener {
OnFragmentChangeListener onFragmentChangeListener;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onFragmentChangeListener=(OnFragmentChangeListener) getActivity();
}
#Override
public void OnActivityBackPress() {
// pass you data to activity for loading new fragment or to refresh data.
Bundle bundle= new Bundle();
onFragmentChangeListener.OnFragmentChange(bundle);
}
}
// interface behave like mediator
public interface OnBackPressListener {
public void OnActivtiyBackPress();
}
Use interface to achieve this. Implements interface in fragment and activity, as it's a good way to communicate between fragment through activity. Then send the data through interface and extract the data from it.
You can use Interface class to communicate between fragment but it must make sure all the fragment is alive.
You can use SharedPreferences where you can save the data and retrieve it anywhere you like
So i have a FragmentPagerAdapater called SectionsPagerAdapter and a fragment called TeamFragment where I display data from a specific team. So basically I don't want to create different fragments for each team. That is an overkill. I just want 1 fragment which basically connects to the backend then collects the data based on the team then displays that data. But I dont know how to pass the Team name(a string type) from SectionsPagerAdapter to the TeamFragment so that in TeamFragment, I can easily know what to retrieve from the backend. My backend in parse.com. Please help me figure this out and learn. Thanks
So this is was solved my problem. In my sectionsPagerAdapter class i had the below code
Bundle args = new Bundle();
args.putString("TeamName", team);
TeamFragment teamFragment = new TeamFragment();
teamFragment.setArguments(args);
In onCreateView of my TeamFragment, i had the following
Bundle bundle = this.getArguments();
mTeam = bundle.getString("TeamName");
hope this can help someone else. Thanks
Communicating data into fragments is typically done through a simple setter function that is called by the activity that instantiates or contains the fragment:
public class MyActivity extends FragmentActivity {
#Override
protected void onCreate(Bundled savedInstanceState) {
// ...
TeamFragment fragment =
(TeamFragment) (getSupportFragmentManager().findFragmentById(fragmentId));
fragment.setTeamName(teamName);
// ...
}
For communicating data back to the activity, is typically done using a fragment-specific "Listener" interface. This listener can be attached using the same method (by calling a method on the fragment in the parent activity to register the listener) or it can be done by requiring that the parent Activity implement the listener interface, and casting the parent activity to this listener interface in onAttach() (though the latter approach is not as clean of an approach). Example:
public class MyActivity extends FragmentActivity {
#Override
protected void onCreate(Bundled savedInstanceState) {
// ...
TeamFragment fragment =
(TeamFragment) (getSupportFragmentManager().findFragmentById(fragmentId));
fragment.setTeamName(teamName);
fragment.setTeamSelectedListener(new TeamSelectedListenerImpl());
// ...
}
Or:
public class TeamFragment extends Fragment {
public interface TeamSelectedListener {
// ...
}
// ...
#Override
protected void onAttach(Activity activity) {
teamSelectedListener = (TeamSelectedListener) activity;
}
// ...
}
public class MyActivity
extends FragmentActivity
implements TeamFragment.TeamSelectedListener {
// ...
}
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
I'm sure this question has been asked lots of times but didn't find any useful answer.
I'm trying to implement Fragment which can be use in my app for X times (yes yes..even 100 and more..)
I want to create my fragment only once and in other times to pass bundle and make lifecycle do what he needs to do with the bundle data.
So far so good? So what i've found is a nice implementation from google document:
public static class MyFragment extends Fragment {
public MyFragment() { } // Required empty constructor
public static MyFragment newInstance(String foo, int bar) {
MyFragment f = new MyFragment();
Bundle args = new Bundle();
args.putString(ARG_FOO, foo);
args.putInt(ARG_BAR, bar);
f.setArguments(args);
return f;
}
You can then access this data at a later point:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
// Use initialisation data
}
}
So what's wrong here? First, the Fragment MUST be an inner class. Second, if the class is static, and the function newInstance(...) is static, why they always create new instance without checking (By keeping a static member of the fragment) if it's not null like a Singleton ?
Assuming my fragment will be added many times to my fragment manager, can I use my fragment class as full Singleton? it means that each time I'll call:
public class MyFragment extends Fragment {
private static MyFragment sInstance;
public MyFragment() { } // Required empty constructor
public static MyFragment newInstance(String foo, int bar) {
if (sInstance==null) {
sInstance = new MyFragment();
}
Bundle args = new Bundle();
args.putString(ARG_FOO, foo);
args.putInt(ARG_BAR, bar);
f.setArguments(args);
return f;
}
}
Than use the new/exist fragment to make the transaction.
Hope I make myself clear, and didn't write some nonsense here :)
Thanks very much for your help