My fragments in viewpager tab dont refresh - android

i got viewpager with 4 tabs .. in each tab there is a fragment.
my first tab is a fragment with a form (for example Users)
after i click save, the data is inserted in the database.
my second tab is another fragment with form but it uses data from the first tab (i am getting it from the database) to populate a spinner.
now after i successfully inserted data from my first tab, in my second tab the spinner is empty. since my db query is implemented in onCreateView() in the second fragment, its called only once when the application is started, so changing between tab 1 i tab2 doesn't starts onCreateView() or even onResume().
The interesting thing for me is that if i go to tab4 and then return to tab2, my data is in my spinner properly, so somehow swiping two tabs away from my current tab refreshing my fragment.
my question is how can i achieve proper refresh to my fragment when onCreateView() is called only once ?
Edit
i tried to put that method psykhi suggested like that:
this.mViewPager.setOffscreenPageLimit(0);
this.mViewPager.setAdapter(this.mPagerAdapter);
this.mViewPager.setOnPageChangeListener(this);
but it's not working for me. Am i missing something ?

The best way that I have discovered to simulate a "setOffscreenPageLimit(0)" behavior is by using an OnPageChangeListener in conjunction with overriding the getItemPosition method in your adapter. Something like this:
In your custom pager adapter:
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
Then in your Activity containing the ViewPager:
final MyPagerAdapter adapter = new MyPagerAdapter();
pager.setAdapter(adapter);
pager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
... anything you may need to do to handle pager state ...
adapter.notifyDataSetChanged(); //this line will force all pages to be loaded fresh when changing between fragments
}
}
This should have the same effect as setting the OffscreenPageLimit to 0. However, this functionality is sort of against what the ViewPager is designed to provide. If you are trying to implement a ViewPager in this way, it may be worth reevaluating your layout to be sure that a ViewPager is really what you want to use.

UPDATE: There is a better way, Please have a look here: Update ViewPager dynamically?
Removing content of this answer because it was a really bad way to access Fragments inside ViewPager, please see the above link for better approach.

It's because you can specify the number of fragment your viewpager will "keep in RAM" (setOffScreenPageLimit () :I think the default is 1). So your second fragment is not reloaded. And when you go to a tab 3 or 4, then your 2 firsts fragments are deleted, then recreated when you come back.
To refresh your fragment, there is many way to do it: you could implement a listener interface of your own in it to tell it when to refresh, or simply call a method that you would implement to update your contents.

first override in the fragment method
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
actionView();//call the method to be refreshed
}
else{
//no
}
}

In my experience, ViewPagers keep:
Your current tab
& 1 tab either side in memory
So when you switch between 1 and 2, nothing is happening under the hood - it's like they are simply being hidden / shown.
But when you navigate to tab 4, tabs 1 & 2 are destroyed (onDestroy() called), so when you navigate back to either of them, they are being re-created fresh (onCreate() called).
As psykhi suggests, you could setOffScreenPageLimit() to 0, so that each fragment is created every time you navigate to it.
If you were interested in keeping the other pages in memory for performance purposes, as they were designed with this is mind, you could use a messaging/event publishing system to send a message from tab 1 to tab 2 telling it to update when you submit the form on tab 1.

Ok may be a late reply,might help others in future, so recently I faced same issue while fetching data from db into tabs it used to display only once I click on 3rd tab.. I tried above mentioned solution but nothing really worked.. fianlly i came across Otto
This library allows you to communicate within your app..
Just use this library to yourAdapter.notifyDataSetChanged() wherever you fetching your data from db..
This video helped me alot https://www.youtube.com/watch?v=lVqBmGK3VuA

Related

xamarin android viewpager fragments not getting refreshed

I'm using this sample to create a simple app, it's made by Joshep Raco (JoeRock11)
https://github.com/JoeRock11/Xamarin_DesignLibrary
I have a problem, I was working with this sample to create a tabbed app, and I found an strange behavior, when the app is starting only the fragment1 and fragment2 loads , but not the fragment3 (when I say load I mean their oncreate and oncreateview method gets triggered ).
To load the fragment3 I have to explicity click it, I thought all the fragments would get load but is not the case, don't know why, I would like to know why this happens.
Also, and this is my main problem and I dont know how to fix it, every time I click a fragment tab, I want this fragment to reaload, now seems like it just shows the instantiated fragment on memory, because it doens't triger any method of the fragment, I need to load it again, because I need to refresh its data, now it only reloads randomly. can you or anyone help me solve this please?
Thanks a lot in advance.
pd: sorry for my english, it's not my mother language.
I believe this is controlled by the Off Screen Page Limit on the ViewPager control. This value defaults to 1, which basically means, the number of the pages the ViewPager should load at a time is 2, the page that is currently displayed, and the one off screen.
This value can be easily adjusted using the OffscreenPageLimit property on the ViewPager.
http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit(int)
If you want all Fragments to reload data once they are slid on to the screen, you can override UserVisibleHint on each Fragmentand then check to see if the Fragment is visible and execute some code to reload data for that fragment:
public override bool UserVisibleHint {
get {
return base.UserVisibleHint;
}
set {
base.UserVisibleHint = value;
if (value) {
//Fragment is visible, reload data
}
}
}
http://developer.android.com/reference/android/support/v4/app/Fragment.html#setUserVisibleHint(boolean)
Another approach to updating the ViewPager fragments is outlined here: Update ViewPager dynamically?

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.

Not all Views inside ViewPager's Fragments will update

I have 3 Fragments inside my ViewPager.
Inside my Fragments I added static ToggleButtons.(static, because I didn't find a workaround for a nullpointerexception, if I wanted to use findViewById() inside my Fragment classes in custom methods and not in onCreateView() )
Outside the ViewPager in my MainActivity I have a Reset-Button, that should reset all ToggleButtons (on all 3 Fragments) to "unchecked".
Every time i click on the Reset-Button, only the current Page and every neighbor-page gets updated.
E.G.
Current Page : 0 Updated Pages: 0,1
Current Page : 1 Updated Pages: 0,1,2
Current Page : 2 Updated Pages: 1,2
I think the Problem is the FragmentPagerAdapter. The Documentation says :
Implementation of PagerAdapter that represents each page as a Fragment
that is persistently kept in the fragment manager as long as the user
can return to the page.
When I'm on Page 2 i can not directly return to Page 0 , so I think the Views from Page 0 (= Fragment 0 ) are not in memory anymore?!
So how can I access the ToggleButtons inside a Fragment that is not visible at the moment nor is a neighbor of the current Fragment ? Is there any workaround?
EDIT:
I found out, that in deed all checked()-values of my ToggleButtons (on ALL Fragments) get updated, but not the inflated Views of Fragments, that are not visible and not neighbor Fragments. So when I return to those previous Fragments, the checked()-values of the ToggleButtons are reset to the state last time the fragment was visible. strange...
Example:
Page2 active - ToggleButton_Page2.checked() = true
switch to Page 0
press Reset-Button. Toast ToggleButton_Page2.checked() = false
switch back to Page 2 (or already at Page 1)
ToggleButton_Page2.checked() = true //it should be false
SOURCE:
Example Source Code
So how can I access the ToggleButtons inside a Fragment that is not
visible at the moment nor is a neighbor of the current Fragment ? Is
there any workaround?
You have a lot of problems in your code, you should read a bit more about Fragments and using them in a ViewPager.
In the reset and status buttons OnClickListeners listeners you write _adapter.getItem(x); in an attempt to get a handle to the Fragment representing the page at that position. This will not work as simply calling that method will return a new instance of the Fragment at that position and not the actual Fragment the ViewPager used(by calling getItem() at previous moment). That new instance you get after calling getItem() is not tied to the Activity and its onCreateView method wasn't called so it has no view(and you get the NullPointerException when you access it). You then tried to get around this by making the ToggelButton as a static field in the Fragment which will work as the field will be initialized when the ViewPager properly creates the Fragments at start. But you shouldn't do this, static fields that hold references to the Context(like any View does) are dangerous as you risk leaking that Context.
Also, related to what I said above, you don't need to pass a Context to a Fragment as a Fragment which is tied to an Activity has the getActivity() method which returns a reference to that Activity.
You shouldn't access any fragments from the ViewPager which aren't near to the visible fragment(one on the left/right of the visible position, unless you don't play with the setOffscreenPageLimit() method of the ViewPager). The ViewPager has a mechanism to improve performance(like a ListView does) so it only creates what it needs immediately so it can provide a smooth swipe for the user.
I've made some changes to your project, check them out. For further questions please post the relevant code in your question.
Salut,
Thank you for your good information, and the improved code!
"But you shouldn't do this, static fields that hold references to the
Context(like any View does) are dangerous as you risk leaking that
Context."
I'm new to Fragment implementation, and spent hours of finding out how the input String is correctly used for findFragmentByTag().(Now knowing how to use it I never thought that it would be that complex). So I decided to do that static workaround, which wasn't a good idea...
As I understand you, i CAN access more then +-1 Fragments, for example if I use setOffscreenPageLimit(3). I think this is the answer to my question.

Updating ListView inside Fragment (ViewPager)

i've a simple chat application with ViewPager for Active Chats, now, i use
#Override
public int getItemPosition(Object object)
{
return POSITION_NONE;
}
but this causes the all fragments to be recreated, and if there is too many messages it will lag, and also it closes keyboard whenever a message is received, so i attempted to override instantiateItem, but i couldn't get to anywhere, since i didn't know what to do with it, i wanted to update all listviews/fragments, not just the active one.
i also tried to use the onCreateView of fragments, get the listview, add an adapter to it, and add that adapter to a Array list, and whenever each messages comes, all adapters in this array list are updated, but this didn't work as expected, i had to move away from ViewPager then back to it again (Since the ViewPager is inside a tabHost) for messages to be displayed.
any help is appreciated, thanks.
Please use setTag() method in getItemPostion() for the views to update them rather then returning POSITION_NONE. The reason of using setTag() and the way how to do that is well explained in this post ViewPager PagerAdapter not updating the View

ViewPager + FragmentStatePagerAdapter : need to know when fragment is displayed (selected)

I am using a ViewPager plugged to a FragmentStatePagerAdapter. Each fragment contains a listview. In this listview I wish to display ads and make calls to a analytics server. I only want to make those calls when the user navigates to a fragment (so I cannot use the onCreateView or onActivityCreated events in the Fragment). Is there an event I can hook on to this end ?
Update
I realized that the way I am fetching my current fragment is flawe
#Override
public void onPageSelected(int page) {
this.currentPage = page;
tabsAdapter.getItem(page);
}
getItem(int position) in the pager is actually responsible for instanciating the fragments, so it would create a new unattached fragment (hence getActivity() returning null). I think I will us an approach where I keep a map of the fragments (<Position, Fragment>), i will remove the fragment from the map when destoryItem is called in the pagerAdapter.
You are right, best option is the second solution here:
http://tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part-ii.html
so your thoughts are correct.
How about this:
http://developer.android.com/reference/android/support/v4/view/ViewPager.OnPageChangeListener.html
The onPageSelected(int) method sounds like it does what you want.

Categories

Resources