Sharing data between android fragments - android

I have two fragments.
The checkNodesFragment creates dynamically an ArrayList of checkBoxes and then
the ReserveNodesFragment should access which of them were checked in checkNodesFragment.
What storage method is better to use, so as ReserveNodesFragment can see what checkBoxes where checked?
After searching, i found that SharedPreferences is a method to store data permanently. Is SharedPreferences suitable for making data visible through fragments?
I am newbie in android, so sorry if the question is obvious.

The communication between fragments should be done via Activity.
Sharing Data between Activity to Fragment
Create a bundle and use fragment.setArguments(bundle) to pass data to Fragment.
Sharing Data between Fragment to Activity
create an interface in your fragment and in your Activity implement the interface
More info:
Communicating with Other Fragments (Download the sample).

If you wish to transfer data across fragments in runtime you can simply use Activity.
Every fragment has method getActivity(). It's a kind of parent for your fragments so you can use it as a "bridge". Nice solution would be defining callbacks in your fragments. Then your Activity could be working as registered observer for these callbacks and react accordingly e.g. listen for changes in the first fragment and then set something on the second fragment.
In more details.
Define interface in your fragment that provides information about changes. Create method that will be called in fragment when checkbox is selected.
In onAttach() method check if getActivity() is instance of that interface
Make you Activity to implement that interface
Implement method in Activity. Inside that method call second fragment and pass updated information.
Nice example can be found when you create an Activity from a template with fragment in Android Studio.

As i mentioned, i have two fragments. checkNodesFragment creates dynamically an ArrayList of checkBoxes and then the ReserveNodesFragment should access which of them were checked in checkNodesFragment .
But i have six Arraylists of checkBoxes that ReserveNodesFragment should know:
//The ArrayLists with the checkBoxes
public ArrayList<CheckBox> orbitCheckBoxes = new ArrayList<CheckBox>();
public ArrayList<CheckBox> gridCheckBoxes = new ArrayList<CheckBox>();
public ArrayList<CheckBox> usrpCheckBoxes = new ArrayList<CheckBox>();
public ArrayList<CheckBox> disklessCheckBoxes = new ArrayList<CheckBox>();
public ArrayList<CheckBox> icarusCheckBoxes = new ArrayList<CheckBox>();
public ArrayList<CheckBox> baseStationsCheckBoxes = new ArrayList<CheckBox>();
So according to your suggestion i should pass six parameters to the method of the interface, so as ReserveNodesFragment will have access to the six ArrayLists:
// Container Activity must implement this interface
public interface OnHeadlineSelectedListener {
public void onReserveSelected(ArrayList<CheckBox> orbitCheckBoxes, ArrayList<CheckBox> gridCheckBoxes, ArrayList<CheckBox> usrpCheckBoxes, ArrayList<CheckBox> disklessCheckBoxes,
ArrayList<CheckBox> icarusCheckBoxes, ArrayList<CheckBox> baseStationsCheckBoxes);
}
So it is elegant to pass so many parameters to the callback method?
Also, the checkNodesFragment is a nested fragment to the AvailableNodesFragment. So its parent is not an activity but a Fragment.
So the app hierarchy is like this:
NitosSchedulerActivity --> AvailableNodesFragment-->CheckAvailableNodesFragment
NitosSchedulerActivity --> ReserveNodesFragment
The CheckAvailableNodesFragment is a nested Fragment to AvailableNodesFragment.
The ReserveNodesFragment is triggered by a Button of the AvailableNodesFragment.
So, there is not a way to trigger a callback method from CheckAvailableNodesFragment to
ReserveNodesFragment for passing the ArrayLists.
So, until now the only way i found to make the ArrayLists of CheckBoxes visible to the ReserveNodesFragment is to make the ArrayLists declared globally.
However, making ArrayLists global is an elegant solution?

Related

How can I gather data from my ViewPager?

I made an activity which is simply a viewpager with a few tabs. Each tab is like a form that the user needs to fill out. When the user is done, the data from the view pager should be collected and sent back as a result. I almost have this working but for some reason the data on my first tab seems to get reset when the user gets to the third tab. I'm guessing this is due to some view recycling in the pager. Anyways, I'm wondering if there is some easy way to gather all the data from the different tabs or do I have to create some kind of tight coupling between the activity and viewpager object?
you have to use SmartFragmentStatePagerAdapter as described here "https://guides.codepath.com/android/ViewPager-with-FragmentPagerAdapter" and than need to
vpPager.setOffscreenPageLimit(3);
Your issue should be resolved. :)
A viewpager will kill off the fragment if it is 2 pages away from the current page. It then recreates it when the pager is on a page that is 1 step away from it.
You should move your form data into your activity/fragment that is holding the viewpager and use fragment listeners to update your data accordingly
For example, you could use a fragment listener like below to pass the data to/from the containing activity
public interface MyFragmentListener{
void saveMyFormData(MyFormData formData);
MyFormData getFormData();
}
private MyFragmentListener mListener;
//initialise fragment listener in onAttach (or elsewhere)
private void initFormView(){
MyFormData data = mListener.getFormData();
//do stuff with data
}
private void saveData(){
mListener.saveMyFormData(myFormDataObject);
}

How to make DialogFragment call a method inside another Fragment

I have a tabbed activity that shows a fragment by a viewpager, as usual.
This fragment have a list.
One of the actions of the user shows a dialogfragment to user insert a new item in this list.
I show the dialogfragment with edittexts to user create a new item.
The question is: how can I insert this item on the viewpagers' fragment list?
From any fragment I can call getActivity() to access the activity, but how access another fragment that is being shown behind the dialogfragment?
Thanks in advance.
Fragment with the List items - FragmentA
Dialog - NewItemDialogFragment
The method you're missing is setTargetFragment(). While building your NewItemDialogFragment, invoke this method passing the FragmentA as the target fragment for your dialog.
Later, you can access the FragmentA instance by calling getTargetFragment() inside NewItemDialogFragment and cast it to the FragmentA and add newly created item.
Alternatively, you can create the contract interface between the FragmentA and the NewItemDialogFragment
It sounds like you want to get the results from the dialogfragment (what the user has inserted on the dialogfragment edit-texts) and use this in the fragment that called the dialogfragment (to add as new item to the list) - in that case, the selected answer here solves this problem - also I think this Gist is a good resource to reference.
In your case, I also think implementing some sort of a custom listener/callback as they did in this Gist is a good idea. Hope this helps.
You can use event bus for this.
http://square.github.io/otto/
This is an example of usage:
Bus bus = new Bus();
bus.post(new AnswerAvailableEvent(42));
#Subscribe public void answerAvailable(AnswerAvailableEvent event) {
// TODO: React to the event somehow!
}
bus.register(this); // In order to receive events, a class instance needs to register with the bus.

ViewPager fragments handling a change

When viewpager displays one fragment, it will automatically load the fragment pages around it for performance reasons.
In my fragments, i have recycleviews with a popup menu to delete one item in the list.
I am facing a problem of deleting one item from one fragment, but that item still exists in the other preloaded fragments after I scroll to them.
It works only if I force the viewpager to reload the contents of its fragments by manually scrolling back and forth the fragments.
Is there a way to force reload the preloaded fragments by viewpager?
Your problem can be solved by using Interface. Google suggest using callbacks\listeners that are managed by your main Activity for communicating between fragments.You can use Interface which tells the other fragment to refresh its listview when you delete an item in current fragment.
For an overview http://developer.android.com/training/basics/fragments/communicating.html
Also a good question about this How to pass data between fragments
First create an interface to detect changes in your RecyclerView:
public interface MyRecyclerViewChangeListener(){
void onRecyclerViewDataChanged(int id);
}
Create a static variable in your Fragment or Activity which contains your viewpager:
public static List<MyRecyclerViewChangeListener> mListeners = new ArrayList();
Implement your interface to your ViewPagerFragments and do what you want in method you implemented.
In your fragment's onResume register your listener to mListeners like blow to detect changes:
MyFragmentOrActivity.mListeners.add(this);
And in your fragment's onPause unregister your listener:
MyFragmentOrActivity.mListeners.remove(this);
Finally notify your listeners when your recyclerview data changed:
for(MyRecyclerViewChangeListener listener : mListeners){
listener.onRecyclerViewDataChanged(id);
}
Edit : If you are changing your recyclerview's data after an async task result such as a web api call, you can register your listener in fragment's onCreateView method and un register in onDestroyView method. So you can catch changes in your fragments.
I am not sure if i'm getting your question right but i think this should do it.
YourViewpager.setOffscreenPageLimit(0);
Now the fragment should be destroyed if it is not active and will be recreated if you open it again.So the data change should be recognized.
Hope I could help
Try setting mViewPager.setOffscreenPageLimit(1) such that it will not pre-cache any fragment or you could use FragmentStatePagerAdapter inside viewPager to achieve what you want.
Edit 1:
So Conclusion is :
1) Use local broadcast mechanism to update the fragments present in ViewPager adapter
2) Use handler mechanism to refresh these fragments
3) if you want to blindly update these fragments once they are visible to users then do it inside onPageChangeListener of view pager method.
The answers helped me find the solution.
For future reference, I used a callback every time I used deleteItem(), and took a list of the loaded frags by using the method [FragmentHostingViewPager].getChildFragmentManager().getFragments()
Then I iterated through each fragment as long as each fragment was not null, and called a refresh() method on them.

How to reuse ListFragement in given setup on some event

This what I have
XListActivity.class
It inflates LinearLayout and creates one Fragment, YListFragment
YListFragment.class
Inflates LsitView from xml and setup a adapter which extends base adapter
Now on some event (e.g. onClick), I want to reuse same fragment and ListView whith different set of data.
If I handle OnClick() event in XListActivity then I don't have reference of ListView and Adapter created in yListFragment. I need them to empty adapter. I want to avoid static references.
How can I achieve this?
You can get your fragment by tag or id using the FragmentManager.
YListFragment fragment = (YListFragment)getFragmentManager().findFragmentByTag("ylistfragment");
fragment.somePublicMethodInYListFragment();
Activity -> Fragment and Fragment -> Activity communication guidelines are outlined here

"Refreshing" a fragment from the MainActivity

So, there is a button in a ListFragment. The onCLick method of the button is implemented in the MainActivity(not sure if it is a proper solution, but it is what it is). When I click the button the AlertDialog pops up and when I choose one of the dialog options it changes the dataset my fragment is working with.
The problem is when the AlertDialog disappears, my ListFragment is still displaying old data.
Is there any way to update my ListFragment from the MainActivity?
I've tried making certain ListFragment methods static so that they could be called from the main activity, but those methods use non-static fields, etc. and thus cannot be static.
You should be able to update ListFragments by calling notifyDataSetChanged() on it's adapter (assuming that your adapter derives from BaseAdapter or any of it's subclasses). The easiest way to do this would probably be set an an DialogInterface.OnDismissListener on your dialog.
myDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog){
myBaseAdapter.notifyDataSetChanged();
}
});
You can either keep the reference to the Adapter or get it directly from the ListFragment depending on your implementation.
So, I declared an adapter of my ListFragment fragment as static, as well as the I declared a list from which this adapter is being filled - as static.
From the main activity I do this:
ListFragment.item.add(mChosenFilePath);
ListFragment.fileList.notifyDataSetChanged();
where:
item - is a list that contains the elements that are to be displayed
mChosenFilePath - path of file that has been added into the item as a result of the dialog
fileList - is my adapter
Set a tag, or id for the fragment. You can then call a method directly on the fragment from the Activity:
Fragment myne = findFragmentByTag( "MyFragment" );
MyFragment target = (MyFragment) myne;
target.refresh(); // 'Refresh' method to be declared by MyFragment implementation
There are three possible solutions.
Listen for the click in your fragment instead of the Activity.
Set a listener on the cancel button of your dialog, and reload the fragment as needed.
Add your fragment with a tag, get it from the manager by that tag, and call the appropriate method.

Categories

Resources