i have 2 fragments
in 1st fragment i am calling a 2nd fragment on button click which returns data(on click on list items) and again open 1st fragment with the result displayed (i.e some String data of list item).
But the problem is when i comeback from 2nd to 1st again after selection in 2nd fragment my 1st fragment is displayed only but do not react on button click.
this is my first fragment
i have searched lot but i found activity fragment communication only not fragment to fragment
if any body has solution for fragment to fragment only.please help
There are a lot of ways, here some hints.
Generally speaking you can use "listeners" (interfaces)
Official Google Docs
Similar question on StackOverflow
More elegant way using "event bus" paradigm, a clean and simple library is Otto
Another (slightly dirty) way if you are using the compatibility library would be to use the LocalBroadcastManager. Your fragments can send (and listen for) local broadcasts to notify each other of events...
Try like this (Example an integer array):
//Create a public class:
public class Values{
public static int[] val = null;
}
//Set array in one fragment:
Values.val = int[] arr1;//arr1 containing your values
//Get array in another fragment:
int[] arr2 = Values.val;
Related
I have an Activity that contains a ViewPager with four tabs .
each tab has a fragment.
When I click something in tab 4, I want tab 3 to refresh(or access a non-static method in tab 3 ) ..I've searched but all I found had this in it:
FragmentB fragment = (FragmentB)getFragmentManager().findFragmentByTag("FragmentB");
and I can't use it since I never set a tag on the fragment.
I also could call a function from fragment in another fragment but it has to be static , and I don't want that since everything inside it must be static too and that would mess things up for me..
is there a solution to this ?
First of all i think it's not a good practice to update a view which user cannot see on screen at the moment. It's much better to update your data when user navigates to screen. By the way it not our first concern now.
I'm not sure this is still a valid way to find Fragments in a ViewPager byTag but you can find them like below:
This method generates default Tag for a Fragment in ViewPager.
#NonNull
public static String generateViewPagerFragmentTag(int viewPagerId, int position) {
final StringBuilder tagBuilder = new StringBuilder();
tagBuilder.append("android:switcher:");
tagBuilder.append(viewPagerId);
tagBuilder.append(":");
tagBuilder.append(position);
return tagBuilder.toString();
}
Than you can use this tag to find your Fragment with findFragmentByTag method.
Also as mentioned in comments you can use an EventBus library to achieve what you want to do but be careful of Fragment Lifecycle states in ViewPager because the Fragment you want to communicate can be in onPause state an your changes canned be received. This depends on in which lifecycle method you subscribe and unsubscribe to bus. (If you are using OttoBus you can get no subscribers found for this event exception.) You can do same pattern with interfaces. You can create an interface and implement in your Fragments.
For an other solution, you can directly access our fragments in your ViewPager. Here's my answer for another question it.
Finally, as i mentioned at the beginning i think you should implement a solution which updates your data when user switched to specific tab of ViewPager. You can keep your data changes in a mem-cache and listen tab changes and update your view when user exactly navigated to that screen and ready to see data changes. You can check Repository pattern for a more complex solution.
What I would like to achieve:
I have a flow where a user can choose among groups/categories of items (first tab) and see the list of items (in the second tab) and do other things in the third tab (not important here)
When the user lands on the application the first time the default group/category is chosen (in the first tab) and the corresponding list of items is displayed (in the second tab)
When the user selects a different group (in the first tab) I would like to change the list (in the second tab).
so the main question is:
What is the best and correct way to achieve this?
My current Implementation:
UI: Swipe Views with Tabs
I've choosen a layout with tabs and swipe view. Each tab is a different fragment declared in a FragmentPageAdapter. Everything contained in a ViewPager as explained in tutorial at https://developer.android.com/training/implementing-navigation/lateral.html
Backend: Firebase
Each fragment takes data from Firebase DB as list of objects through a FirebaseRecyclerAdapter.
Trying different solutions... What do you think is the best approach?
1. Use a different Layout?
Implement the user flow in a different way without swipe views
For example, It could be a floating button to first choose a group of items and then see them in another activity, but in this way coming back to groups/categories is not easy as with swipe views.
2. Dinamycally Change Fragment in TAB2?
When the user select a group in TAB1 create a new fragment initalised with a different DatabaseReference and change it in TAB2 through FragmentManager.
I've read many posts here on StackOverflow about dinamically changing
fragment in ViewPager but I didn't find really a definitive way to do it. (nested fragments? holder fragment for viewpager?...)
3. Change the Firebase backend reference only?
The idea is to change the Firebase DatabaseReference used to initialise the FirebaseRecyclerAdapter so that a new list of items is loaded, using the same fragment declared in FragmentPageAdapter.
I still didn't find a solution on how to do this
Before speaking of implementations... any idea about the best approach?
In my opinion, I will use EventBus or RxJava.Another implemention is :
STEP1:
Send chosen data in your first tab to Activity.
STEP2:
Send data to second tab from Activity
STEP3:
In second fragment, you can use load data from database in onCreateView
STEP4:
If your second fragment uses single pattern,you can call adapter.setList(yourList) and adapter.notifyDataChanged()
Easy Solution I found
I used the approach to change the Firebase Adapter using the same fragment already declared in ViewPager and it works fine.
I post here below my code if someone has the same scenario and want to implement in the same way.
In the FyrebaseRecyclerAdapter of the first Fragment (first tab), in populate view method you just create a new Firebase Database Reference and create a new adapter to set in the recyclerview.
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String groupKey = getRef(position).getKey();
// Getting the RecyclerView used by Second Fragment (Second TAB)
RecyclerView mRecyclerView = (RecyclerView)fragmentContainer.getActivity().findViewById(R.id.second_recycler_view);
FirebaseDatabase db = FirebaseDatabase.getInstance();
DatabaseReference dbRef = db.getReference("Groups").child(groupKey)
// Set the new adapter so that fragment 2 update data
FirebaseRecyclerAdapter<Member, MemberViewHolder> mAdapter = new MyAdapter(Member.class, R.layout.member, MemberViewHolder.class, dbRef);
mRecyclerView.setAdapter(mAdapter);
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);
}
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.
I simply want to replace a fragment from the current fragment and add a new one.
I have studied that Replace is Equal to removeCurrent + Add anotherFragment
But in my situation i am facing a Problem. For the first two times it is running properly but after third attempt instead of replacing . it ads the fragment on me.
My approach fails now. Now i am asking that how can i send an id to other fragment like we do in Activities. I have a listView with a ReadMore button. I simply want to show the details in another fragment and want to send the index of a List.
I listen about some Interface but don't know how to implement . or there an easy way for communication. I tried doing it by passing it in Constructor . but it will give me an error . because
how to get currentFragment and hide it?
how to add onBackPressed to fragment.
how to send data between fragments The easy way.
i know how to hide or show a fragment
getFragmentManager().beginTransaction().hide(frag[j]).commit();
getFragmentManager().beginTransaction().show(frag[0]).commit();
also know how to add or replace a fragment
getFragmentManager().beginTransaction().add(R.id.container, frag[i])
//.addToBackStack(null)
.commit();
getFragmentManager().beginTransaction().replace(R.id.container, frag[i])
//.addToBackStack(null)
.commit();
Tell me a better approach to send data and why my layout add instead of replacing.
I recommend using EventBus for Activity/Fragment/Service or any other communication.
There is a good one from Square: http://square.github.io/otto/
Or this one (also very good): https://github.com/greenrobot/EventBus
It makes it simplier and your code gets cleaner.
It is pretty easy to send data to fragment with constructor.
In your fragment class, add constructor like this:
public class MyFragment extends Fragment{
String id;
public MyFragment(String id)
this.id = id;
}
Then, when calling a fragment,you can easily send data like this :
getSupportFragmentManager().beginTransaction().replace(android.r.id.container,new MyFragment("123")).commit();
You can't override onBackPressed within fragment, you can only do that in activity
You can set try set the variables in the fragment as public static then you can declare them before you instantiate your fragment to be shown.
in your onDestroy method of the fragment you can set the variables = null, so they dont take space in memory.
could be smth like this
MyFragment.theString = "A String";
getSupportFragmentManager().beginTransaction().replace(android.r.id.container,new MyFragment()).commit();
And in your fragment
public static String theString;
...
public void onDestroy(){
super.onDestroy();
theString = null;
}