I have an activity A with 3 fragments. Each fragments replaces each other, hence at a given time only 1 is visible.
HomeFragment has 2 textviews wrapped inside 2 cardviews. Each cardview represents a text value which comes from Fragment1 and Fragment2. When I click on say Card1,I get to the Fragment1.
Fragment1 has some cardviews, when I selects any of them I navigate back to HomeFragment and update the cardview text based on my selection in Fragment1.Here is the switch statement, depending upon what card user selects I put that in a bundle and pass it to HomeFragment.
switch (v.getId()) {
case R.id.card_view0:
Fragment1Bundle.putString("Test", "Testing");
bundle.putBundle("Fragment1Bundle", Fragment1Bundle);
fragmentTransaction.setCustomAnimations(R.anim.slideup, R.anim.slidedown, R.anim.slideup, R.anim.slidedown);
fragmentTransaction.replace(R.id.content_frame, fragment);
fragment.setArguments(bundle);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
break;
Fragment2 has same behavior as Fragment 1.
switch (v.getId()) {
case R.id.card_view0:
Fragment2Bundle.putString("Test2", "Tetsing");
bundle.putBundle("Fragment2Bundle", Fragment2Bundle);
fragmentTransaction.setCustomAnimations(R.anim.slideup, R.anim.slidedown, R.anim.slideup, R.anim.slidedown);
fragmentTransaction.replace(R.id.content_frame, fragment);
fragment.setArguments(bundle);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
break;
My challenge is that I am using bundles to pass data between fragments, My home fragment gets updated with the data it from fragment1 but when I go to fragment 2 and after making the selection come back to Home fragment, my fragment1 data is set to default. This is what I am doing in Home Fragments onCreateView()
try {
bundle1 = getArguments().getBundle("Fragment1Bundle");
bundle2 = getArguments().getBundle("Fragment2Bundle");
tv.setText(bundle1.getString("Test") == null ? null : bundle1.getString("Test"));
tv2.setText(bundle2.getString("Test2") == null ? nul : bundle2.getString("Test2"));
} catch (NullPointerException e) {
Log.d(TAG, e.printStackTrace());
}
I know that I am creating a new Homefragment in my fragment transaction in both fragment1 and fragment2, How can I keep just 1 instance of Home fragment around.
Another design recommended by Google is to use the main Activity and 2 fragments (in your case Fragment1 and Fragment2). I can see your problem of passing data bundle to HomeFragment. This suggested design uses MainActivity which is declared static (may be required for scoping issue). And it uses an interface to be established between Activity and a Fragment. I think the interface is easier than passing bundle back to the HomeFragment.
A Google webpage is # Communicating with Other Fragments. This is not just my opinion. A good SO link, I think, is How to pass data between fragments.
Code snippet from the webpage...
An example of Fragment to Activity communication:
public class HeadlinesFragment extends ListFragment {
OnHeadlineSelectedListener mCallback;
// Container Activity must implement this interface
public interface OnHeadlineSelectedListener {
public void onArticleSelected(int position);
}
...
An example of Activity to Fragment communication:
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
}
}
Note:
OnHeadlineSelectedListener is the interface created by the Fragment.
The created method onArticleSelected has a parameter position, which comes from the ListView in ListFragment (in the sample).
You can still set data bundles and send data between Activity and Fragment. However I have not sent back data from Fragment to Activity. I normally use Fragment to handle much of UI updates.
how to pass values from activity to already open fragment and update array-list help me please. when I using interface the array-list size is zero what I do? do not us bundle method.
public class Main2Activity extends AppCompatActivity{
String desc = "data";
OnDataPassedListener onDataPassedListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
String passedArg = getIntent().getExtras().getString("id");
Log.d("data",passedArg);
Scription scription = new Scription();
onDataPassedListener = (OnDataPassedListener)scription;
onDataPassedListener.onDataPassed(passedArg,desc);
}
public interface OnDataPassedListener {
void onDataPassed(String text,String name);
}
}
public class Test extends Fragment implements
Main2Activity.OnDataPassedListener{
.
.
.
.
#Override
public void onDataPassed(String text,String name) {
monthlylists.get(Integer.valueOf(text)).setFood_type(name);
}
Related
I'm trying to send data from an activity to a fragment. I'm not sending data from a fragment to an activity. I've got everything set up correctly other than instantiating the interface listener object in the activity.
public class Activity extends AppCompatActivity {
private FragmentInterface fragmentInterfaceListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// This line below is actually in a button onClick()
fragmentInterfaceListener.sendDataMethod(dataToSend);
}
public interface FragmentInterface {
void sendDataMethod(SampleData sampleData);
}
}
Then in the fragment, I have:
public static class CustomFragment extends Fragment implements Activity.FragmentInterface {
#Override
public void sendDataMethod(final SampleData sampleData) {
}
}
When I put a log line in the button onClick(), the log line appears when the button is clicked. No, I'm not going to put the sampleData in a fragment bundle. Yes, I need to send the data through an interface. So how do I correctly instantiate the fragmentInterfaceListener object in the Activity? Am I missing anything else in the Activity or CustomFragment?
What your are missing here is the registering part.
The fragment has to register itself with the activity listener for the activity to send data when an event occurs.To do this create a method in activity
private void setOnDataListener(FragmentInterface interface){
fragmentInterfaceListener=interface;
}
And in the oncreate of your fragment set the listener like this
((YOUR_ACTIVITY_NAME)getActivity()).setOnDataListener(this);
You don't need to use listener in the Fragment because you can directly communicate with the Fragment from its host Activity.
As #lq-gioan says, you can create a public method in your Fragment then call it from your activity. So, create a public method to set the data, something like this:
public static class CustomFragment extends Fragment {
// public method to be accessed by host activity.
public void sendDataMethod(final SampleData sampleData) {
}
}
Then you can call the method within your host activity:
CustomFragment fragment = (CustomFragment)getSupportFragmentManager()
.findFragmentById(R.id.fragment_id);
// or use find by tag if you adding the fragment by tag
// CustomFragment fragment = (CustomFragment)getSupportFragmentManager()
// .findFragmentByTag("FragmentTag");
// now you can call it
fragment.sendDataMethod(yourSampleData);
For sending data from Activity to Fragment we don't need an interface.
You can directly call the method in Fragment or pass as setArguments in Bundle
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();
}
You can refer https://developer.android.com/training/basics/fragments/communicating.html
I have done many programs, where I have implemented multiple Fragments inside a Single Activity, but not when using Single Activity to host multiple Fragments as Tabs and then on Tap show another Fragments...
Using MaterialViewPager library, in which I am calling different different Fragments to show views in their respective Tabs.
Like For the First Tab, I am using two Fragments, where
In First Fragment, I am using RecyclerView... to show list of Menus.
And in Second Fragment, I am using RecyclerView... to show list of Items under particular Menu.
So here my question is How to call Fragment from Fragment.
mRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), mRecyclerView ,new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
Value value = valueList.get(position);
List<Learning> learning = value.getLearning();
// using when putting "item" data into same recyclerview
// but on back press just exiting, not showing list of Menus again
/**
learningAdapter = new LearningAdapter(learning, R.layout.card_learning, getActivity());
mRecyclerView.setAdapter(learningAdapter);
**/
ItemFragment fragment = new ItemFragment();
replaceFragment(fragment);
}
Method replaceFragment
public void replaceFragment(Fragment someFragment) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// using Fragment not Activity, so where can I use frame_container in xml
transaction.replace(R.id.frame_container, someFragment);
transaction.addToBackStack(null);
transaction.commit();
}
you can have a callback interface that is implemented by the activity which hosts these two fragments. Fragment A will use the call back to notify the activity to replace A with fragment B. Depending on your need, you can pass parameters across through the callback method itself.
Your callback interface:
public interface YourCallback {
public void methodWhichReplacesFragmentAwithB(params...);
}
Your Activity hosting fragments:
public class YourActivity extends ... implements YourCallback {
..
..
#Override
public void methodWhichReplacesFragmentAwithB(params...) {
//insert replace fragment code here
}
}
Your fragment will have a callback object, YourCallback callbackObj;. This callback object can be initialised using the activity (pass as this from activity) itself since the activity has the implementation of the interface. Now, you can use
callbackObj.methodWhichReplacesFragmentAwithB(actual_params...);
to replace the fragment. This callback interface can be exploited for other communications to parent Activity as well as other fragment hosted in that activity.
To replace fragment,
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container, someFragment).addToBackStack("null").commit();
You can try this:
YourFragment fragment = new YourFragment();
FragmentTransaction transaction = ((AppCompatActivity) mContext).getSupportFragmentManager()
.beginTransaction();
transaction.replace(R.id.frame, fragment);
transaction.addToBackStack(null);
transaction.commit();
There is One option which i have been using from long time before. I will added the solution with clear example.
So you want to pass the value from fragment A to fragment B
So, here what you want to do is, you have pass the value through the activity.
1) you pass the value from fragment A to activity
2) then activity to fragment B
Step 1: first create an Interface Like below in fragment A
public interface HomePage {
void onHomeButtonsClicked(String clickedButton);
}
public void setOnHomeButtonClicked(HomePage homePage) {
this.homePage = homePage;
}
Step 2: then create the instance like below in Activity. where fragment created in PagerAdapter
((FragmentA) fragment).setOnHomeButtonClicked(new FragmentA.HomePage() {
#Override
public void onHomeButtonsClicked(String buttonClicked) {
pageSelected.onHomeButtonsClicked(selectedPage);
}
}
});
Step 3: then create the interface in Activity like below.
public interface PageSelected {
void onHomeButtonsClicked(String clickedButton);
}
public void setOnHomeButtonClicked(PageSelected pageSelected) {
this.pageSelected = pageSelected;
}
step 3: then add the following method in fragment B in onCreateView or onResume()
((MainActivity) getActivity()).setOnHomeButtonClicked(new MainActivity.PageSelected() {
#Override
public void onHomeButtonsClicked(String clickedButton) {
//fragment B received the value here
}
});
Step 5: finally add the line in fragment A in button click or where you want to pass the value.
homePage.onHomeButtonsClicked("Some String , by this code it is in String. you can change in your own data type");
You can rise your question if you face any difficulties.
Scenario is: I have two fragments FragmentA and FragmentB.
In FragmentA, I have a simple form and in FragmentB, I am showing data of that form in ListView.
I am getting data in listview but not in real time. Like first I insert data, then, I restart Application to see data in list.
My question is how to notify change from one fragment to another in real time.
you can use listener in your activity and then notify:
class MyActivity extends Activity {
FragmentA fragA;
FragmentB fragB;
public void notifyB() {
fragB.notifyB();
}
class FragmentA extends Fragment{
private void notifyB(){
((MyActivity) getActivity()).notifyB();
}
class FragmentB extends Fragment{
public notifyB() {
// do something
}
}
After setting the variable of the FragmentTransaction you can do like this:
Bundle bundle = new Bundle();
bundle.putString("flag", variable)// You can pass Strings, Int, Boolean.
//The "flag" is the key to get the value in the other fragment.
//The variable is wat you need to pass to the other fragment.
In you new fragment you can get your viable like this:
Bundle bundle = new Bundle();
String a = bundle.getString("flag");
// now you have te value in the variable a
this works in eclipse
Situation:
I have an activity with a FrameLayout in which I change fragments.
I use:
getSupportFragmentManager().beginTransaction()
.replace(R.id.content, fragment)
.addToBackStack("name")
.commit)
All works fine the problem is when I go back in the stack the previous fragment is reloaded and all the data is lost.
Possible solution:
restore fragment state - I want to avoid this because most of the data is retrieved from the server and it takes a lot of time
use .add(R.id.content, fragment) instead of .add(R.id.content, fragment) but in this case my fragments must have a solid background otherwise they overlay each other. The problem is that I can't set a solid background because of some design constraints.
Question:
How can i use '.add(R.id.content,fragment)' and somehow hide the fragment below it so it won't overlay and I can go back to the previous fragment in the state I left it.
First I would say that there's no need to add the fragment to the backstack if you don't want the user to go back to a previous fragment.
To answer the other question, the FragmentManager has a "hide" method that you can use to keep a fragment in the FragmentManager, but hide it from the user. Then use "show" to reveal it again.
final Fragment oldFragment = methodToGetFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.content, fragment)
.hide(oldFragment)
.addToBackStack("name")
.commit)
Like stated in the first sentence, the Fragment is going to be popped and the old fragment will be shown when the user presses "back". If you don't want that to happen, then simply remove addToBackStack().
for save data
you can use Activity when replacing fragments, activity is live .
public class MotherActivity extends ActionBarActivity {
private Data data = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_adv);
Fragment oldFragment = methodToGetFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.content, fragment)
.hide(oldFragment)
.addToBackStack("name")
.commit)
}
public void setData(Data data){
....
}
public void getData(){
....}
}
public class FirstFragment extends Fragment {
private AdvActivity act;
......
public void onAttach(Activity activity) {
super.onAttach(activity);
// get data from internet
Data data=getData();
// and save data in mother activity
activity.setData(data);
}
second fragment:
public class SecondFragment extends Fragment {
private AdvActivity act;
private Data data;
......
public void onAttach(Activity activity) {
super.onAttach(activity);
// get data from mother activity
data=activity.getData();
}
I have listview in one fragment that displays item from a sqlite database. When I click on one item it opens a menu to allow to open, add to another listview or delete. I want to be able to add it to another listview in another fragment on press. I tried adding it to another listview using bundles but I had no luck. I have a plan of creating another database table to store the added data and display it in a new listview. Would this work? or do any of you guys have another suggestion?
You can send data from one fragment to another. The best way to do this is by going through the parent activity. Something like this:
public class MyActivity extends FragmentActivity implements MyFragmentListener {
MyFragment1 frag1;
MyFragment2 frag2;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(0);
FragmentManager fm = getSupportFragmentManager();
frag1 = (MyFragment1) fm.findFragmentByTag("frag1");
frag1.setListener(this);
frag2 = (MyFragment2) fm.findFragmentByTag("frag2");
}
// Call this function from frag1 when you want to send the data to frag2
public void addToFrag2(ListItem item) {
frag2.addToList(item);
}
}
// Define whatever methods the fragments want to use to pass data back and forth
public interface MyFragmentListener {
void addToFrag2(ListItem item);
}