I want my fragment to load only when the tab is clicked. That is I am calling a webservice on each fragment, so I want that webservice to be called only when user clicks the specific tab; loads the fragment.
My Fragments are attached to the view pager.
I have override the following method in my fragments: setUserVisibleHint
override fun setUserVisibleHint(isFragmentVisible: Boolean) {
super.setUserVisibleHint(true)
if (this.isVisible) {
// we check that the fragment is becoming visible
if (isFragmentVisible && !isLoadOnce) {
callAPI(param)
isLoadOnce = true
}
}
}
the variable is set as: private var isLoadOnce = false in the fragment class.
I have 3 fragments in number the problem is when my activity popsup, the first fragment is visible and if I click the last tab that is the third tab to load the third fragment, nothing happens that is the web service won't call at all.
But when I click the second fragment and then the third fragment, and yes the webservice then only calls
So I want to call the web service whenver the user clicks each fragment (number 2 fragment or number 3 fragment)!
Can somebody please figure out what I am doing wrong?
I think there are at least 2 solutions to your problem:
Call "callApi(param)" on onResume() of the fragment;
Override onPageSelected(int) and call "callApi(param) in it.
Let me know if this worked for you!
viewpager generally loads the side views to provide smooth swipe experience.
you can restrict the viewpager to load the view using
viewpager.setOffScreenLimit(0)
Related
I Use a Activity that holds a Fragment Inside That Fragment I have an other Fragment that holds ViewPagger2 now when apps open its should display first child of ViewPagger2 and also lode only that data but its not happening its loads two childs that make my app slow how to solve this issue.
It's the default behaviour of the viewPager2 to load adjacent pages for smoother animation. But you can override the default offscreen page limit by using viewpager2 setOffscreenPageLimit method.
In kotlin use
viewPager2.offscreenPageLimit = PAGE_COUNT
This will load that specified number of pages in advance. But, this PAGE_COUNT cannot be less than 1 which means, It'll still load your second fragment. But, It shouldn't slow down your app as you've mentioned.
If you are doing any network request then you can set registerOnPageChangeCallback for viewPager2 and override onPageSelected, then do the network request only when that fragment is selected.
As onPageSelected(position: Int) only gives us the position of the selected page, but not the fragment itself, so we have to retrieve the selected fragment using childFragmentManager and then trigger our network load request.
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
if (childFragmentManager.fragments.size > position) {
if(position == 1) { // for second fragment
val fragment = childFragmentManager.fragments[position] as SecondFragmentClassName
fragment.loadNetworkData()
}
}
}
})
For multiple fragments you can use when statement accordingly.
Put your data loading in the Fragment's onResume method as Viewpager2 only resumes the Fragment when it is displayed.
This maintains the Fragment's encapsulation but achieves the same goal as doing it in a OnPageChangeCallback.
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?
I have a
1) MainActivity.
2) Fragment 1 (Listview)
3) Fragment 2 (Listview)
4) Fragment 3 (Textview)
I can successfully launch Fragment 1 when the app is first started.
Then, once i click on any listitem on Fragment 1, Fragment 2 is launched. I've handled both these fragments with the following condition in order to differentiate inside my MainActivity
if (this.getIntent().getExtras()
== null) {
fragmentManager.beginTransaction()
.replace(R.id.restaurantlist, Fragment1).commit();
} else {
String id = String.valueOf(getIntent().getExtras().getString(
"restaurant_id"));
fragmentManager.beginTransaction()
.replace(R.id.offerlist, Fragment2).commit();
}
Now how do i move to Fragment 3 by clicking a list item on Fragment 2?
Right now, im also using putEctra AND getExtra "id". For Fragment 2 and Fragment 3. But how do i use it to differentiate inside the above code?
Your question is not clear enough for me. If i get you right you have 3 fragments and there is a situation you want to show them all at the same time (e.g. in tablets). If that is not the case don't use fragments at least the way you are using it right now, Instead use another activity because using fragments where there is no need for them only makes your application more complicated.
Any way i suppose you have 3 container in your activity. when app starts add them all! . also add a onItemClike listener to fragment 1, and fragment 2. so when ever a click on item happens you now about that. Now whenever a click happens inform the other fragment to show the relevant item. to do that you only need to define a public method in fragment 2 and fragment 3.
you can also use fragment manager show() and hide() methods to hide your fragment when necessary.
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
I'm trying to create a ViewPager with six fragments but only 2nd fragment to 5th fragment contain data that I want to show and the first fragment and the last fragment I want to be used to reload the data and set the position to the 2nd fragment again. The overall flow is like this :
1st (reload and go back to 2nd) <- 2nd fragment <-> 5th fragment -> 6th fragment (same with 1st)
what I've tried is I create a callback from the 1st fragment and 6th fragment like this
public static class callbackFragmentLoading implements callbackFragmentLoad {
#Override
public void onLoading() {
mPager.setAdapter(mAdapter);
mPager.setCurrentItem(2,false);
}
}
and I passed the callback to the fragment constructor so I can called the onLoading function in the onActivityCreated. But I everytime I do it the application will be force closed and the logcat shows
recursive entry to executependingtransactions
is there any way to do this? or my method for doing it is wrong?
Thank You
is there any way to do this? or my method for doing it is wrong?
Messing with callbacks between Fragments of a ViewPager isn't probably such a good idea. Instead I would do it like this:
Don't load any data(like with a Loader) in the Fragments from the ViewPager, instead let the FragmentActivity do it(and the Fragments will get it through methods from the Activity).
Your two loading fragments(position 0 and 5) will call in their onResume method a reload action on the parent Activity(like a Loader restart)
At this moment the Activity will load/reload the data and when that finishes it will set the ViewPager to the correct items(either 1 or 4)
in the onResume method of the data fragments you'll refresh the fragment's data(here you may need to use some sort of signaling system because you'll need to duplicate the refresh code in the onCreateView(some fragments may have their view destroyed if they are far apart from the current visible position)).
As I don't know many things about the inner data fragment I've written a basic skeleton sample(without the data loading in the activity).