I have a ViewPager using a TabLayout. I am changing pages within a fragment of ViewPager via parentActivity.setCurrentItem() which directs to a sibling Fragment.
Only when I redirect to this fragment from a sibling I would like to display a different view. I am having a issue since the fragment is being cached and OnCreateView is not firing when the fragment is being displayed.
Is there an event that gets fired when a cached fragment is displayed?
Overriding setUserVisible(boolean isVisibleToUser) in the fragment seems to do the trick. This is triggered when the fragment is created and whenever the fragment is displayed.
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
ParentActivity parent = (ParentActivity)getActivity();
if (parent != null){
String leftMenuToShow = parent.getMenuItemToShowInFragment();
String elementToShow = parent.getElementToShowInFragment();
}
}
Related
I have 10 tabs in my activity. As soon as I open the activity the first fragment gets displayed but the method (AsyncTask) present in the next fragment gets called. And if I go to the next tab say 3rd tab then the method present in the 4th fragment gets called and so on.
I don't understand this behavior. Please help!
You must know how the viewPager works populating the fragment in the different positions
When you start on the position 0, then the fragment on the position 0 and the one of the position 1 are created.
Then when you swipe to the position 1 the fragment on the 2 position is created, so you have now the three fragments created on the different positions (0,1,2..assuming you have only 3 pages on the viewPager).
We swipe to the position 2, the last one, and the fragment on the first position (0) get destroy, so we have now the fragments on the positions 2 and 3.
This is how Fragment LifeCycle Works
you can set mViewPager.setOffscreenPageLimit(2); // 2 is just an example to limit it
If you want some code to execute when Fragment become Visible to User add part of code in setUserVisibleHint method
By default it is viewpager.setOffscreenPageLimit(1) , meaning View pager will by default load atleast 1 on the right and one on the left tab of current tab.
It is done so, mostly because there is a point when you slide viewpager, when certain area of both tabs is visible. For those smooth transitions preloading is required.
You cannot set it viewpager.setOffscreenPageLimit(0).
The only way out is to use this method setUserVisibleHint
add this to your fragment
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// load data here
}else{
// fragment is no longer visible
}
}
This will be called only when that particular tab is visible to user, so only then you can call all loading function.
check sample example
Put your AsyncTask method inside this.
You can override setMenuVisibility like this:
#Override
public void setMenuVisibility(final boolean visible) {
if (visible) {
//execute AsyncTask method
}
super.setMenuVisibility(visible);
}
Happy coding!!
Override below method and move your code for Aync task into this instead of onStart() or onCreateView.
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// Load your data here or do network operations here
isFragmentLoaded = true;
}
}
I'm using viewPager to create a layout with tabs and in each tab I use a Fragment. One of them is to get all de user contacts and put it on a ListView. But I want to call de AssyncTask only if the Fragment is displayed on screen.
is there a method to do it?
TY
Start your AsyncTask in onStart which is the method called once the fragment becomes visible to the user. onCreateView will be called even if the fragment doesn't become visible.
See also: http://developer.android.com/reference/android/app/Fragment.html#onStart()
I would however recommend to use a loader instead of AsyncTask (e.g. an AsyncTaskLoader http://developer.android.com/reference/android/content/AsyncTaskLoader.html).
you can use
#Override
public void setUserVisibleHint(boolean isVisibleToUser)
{
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser)
{
//things to do when fragment is visible
}
}
Even it is called before onCreateView.
You can check to see if it's visible with .isVisible() something like this
MyFragmentClass fragment = (MyFragmentClass) getSupportFragmentManager().findFragmentByTag("fragmentTAG");
if (fragment != null && fragment.isVisible()) {
// call AsyncTask
}
In my application, I have a ViewPager which holds many swipeable Tabs with Fragments inside. Is there a method like onResume which is called every time the fragment comes to the screen? onResume, onCreateView and so on are called after the Fragment is created and not if it comes to the screen, so they do not work for me. Which method can I use for my problem?
You can use setUserVisibleHint method in your fragment:
#Override
public void setUserVisibleHint(boolean isVisibleToUser){
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
// Your fragment is visible
}
}
I'm using a ViewPager to display 2 Fragments as tabs. Once the according activity is loaded, both fragments are loaded immediatly, while only the first one is visible to the user.
Therefore view.isShown() is not sufficent for testing, as this method returns true for the second fragment which is not visible to the user.
ViewAsserts.assertOnScreen(decorView, view) seems to behave the same way and is therefore useless for solving this problem.
I'm aware that some similar questions have been asked, but none of their answers is satisfying my needs. So how to test this behavior (using Robotium)?
Solution:
I solved it according to Leon's suggestion by using a flag within the fragment like this:
private static boolean isVisibleToUser = false;
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
MyFragment.isVisibleToUser = isVisibleToUser;
}
public static boolean isVisibleToUser() {
return isVisibleToUser;
}
implementing it as a static method I can use it in my test this way:
assertTrue(MyFragment.isVisibleToUser());
the only drawback to this solution is that I have to implement these 2 methods in every single Fragment I want to test this way... any improvements?
You could override setUserVisibleHint inside your fragment like this:
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
//Fragment is selected in ViewPager
//Put your "on appear" validation/loading here
}
}
This method will fire every time you show or hide the fragment in the ViewPager.
As opposed to view.isShown() this method does take a "loaded but not visible" state into account.
use OnPageChangedListener to detect changes and maintain a reference to the currently visible fragment/page.
http://developer.android.com/reference/android/support/v4/view/ViewPager.OnPageChangeListener.html
Alternatively GetCurrentItem() may work for you as detailed here: How do you get the current page number of a ViewPager for Android?
I have a ViewPager, each page is a Fragment view. I want to test if a fragment is in a visible region. the Fragment.isVisible only test
the fragment is attached to a activity
the fragment is set to visible
the fragment has been added to a view
The ViewPager will create 3 (by default) fragment and all three of them meet the above criteria, but only one is actually visible to the user (the human eyes)
This is what I use to determine the visibility of a fragment.
private static boolean m_iAmVisible;
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
m_iAmVisible = isVisibleToUser;
if (m_iAmVisible) {
Log.d(localTAG, "this fragment is now visible");
} else {
Log.d(localTAG, "this fragment is now invisible");
}
}
You're right there is a better way to do this!
Have a look at the FragmentPagerAdapter javadoc online and you'll see there is a method setPrimaryItem(ViewGroup container, int position, Object object):void doing exactly what you need.
From the javadoc
public void setPrimaryItem (ViewGroup container, int position, Object object)
Called to inform the adapter of which item is currently considered to
be the "primary", that is the one show to the user as the current
page.
Parameters container The containing View from which the page will be
removed. position The page position that is now the primary.
object The same object that was returned by instantiateItem(View,
int).
Note on scroll state
Now if you implement this and start debugging to get a feel of when exactly this is called you'll quickly notice this is triggered several times on preparing the fragment and while the user is swiping along.
So it might be a good idea to also attach a ViewPager.OnPageChangeListener and only do what has to be done once the viewpagers scroll state becomes SCOLL_STATE_IDLE again.
For my purposes, it worked to use ViewPager.OnPageChangeListener.onPageSelected() in conjunction with Fragment.onActivityCreated() to perform an action when the Fragment is visible. Fragment.getUserVisibleHint() helps too.
I'm using "setMenuVisibility"-Method for resolving this Problem. As every Fragment can have actionbar-items this is the part where you can determine which Fragment is currently visible to the user.
#Override
public void setMenuVisibility(final boolean visible) {
super.setMenuVisibility(visible);
if (!visible) {
//not visible anymore
}else{
yay visible to the user
}
}
What is wrong with using getView().isShown() to find out if a Fragment is actually visible?
isVisible()
Can still return true even if the fragment is behind an activity.
I'm using the following:
if (getView() != null && getView().isShown()) {
//your code here
}
If you know what "page" each fragment is attached to you could use ViewPager.getCurrentItem() to determine which fragment is "visible".
In my case i a have to do some work on the first fragment when the fragment is visible to the user
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(viewPager.getAdapter() instanceof YourPager)
{
Fragment fragemnt=((YourPager)viewPager.getAdapter()).getFragment(0); //getFragment(int index) custom method
if( fragemnt instanceof YourFragment)
{
((YourFragment)fragemnt).methodWhochShouldBeCalledAfterUIVisible();
}
}
}
setUserVisibleHint probably may not be called, onHiddenChanged may be called not every time when another fragment is being closed. So, you may rely on onResume (and onPause), but it is usually called too often (for example, when you turn on a device screen). Also in some situations it is not called, you should manage current fragment in host activity and write:
if (currentFragment != null) {
currentFragment.onResume();
}
Kotlin:
if (userVisibleHint) {
// the fragment is visible
} else {
// the fragment is not visible
}
Java
if (getUserVisibleHint()) {
// the fragment is visible
} else {
// the fragment is not visible
}
https://developer.android.com/reference/android/app/Fragment.html#getUserVisibleHint()
https://stackoverflow.com/a/12523627/2069407