Dont allow viewpager load two page in the first time - android

At the moment, i have a viewpager,when page scroll,i have load api for get new information.
But in the first load viewpager,progress loading display two twice because it load first page and next page.
I only want to load the first page in viewpager.
How must I do?

best way is to create one interface. and implement this interface to all fragment.
e.g.
public interface FragmentInterface {
void fragmentBecameVisible();
}
in ur viewpager activity put like this e.g
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener(){
#Override
public void onPageSelected(int position){
FragmentInterface fragment = (FragmentInterface) mAdapter.instantiateItem(viewPager, position);
if (fragment != null) {
fragment.fragmentBecameVisible();
}
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2){
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
in your fragment like
public class TestFragmet extends Fragment implements FragmentInterface {
#Override
public void fragmentBecameVisible() {
// your task to execute
}
}

Put OffScreenPageLimit to ZERO. It won't load other fragments.
viewPager.setOffscreenPageLimit(0);

Related

How to differentiate 2 viewPager in onPageSelected

my problem is pretty simple but I don't see how to solve it... I didn't find any response to this problem.
I have 2 viewPager and when a page is selected I want to know which viewPager it comes from in onPageSelected().
There is my code :
public class MainActivity {
private ViewPager mCardsPager;
private ViewPager mIpsPager;
private MyCreditCardsPagerAdapter mCardsAdapter;
private MyInstantPaiementPagerAdapter mIpsAdapter;
private List<PayMethod> mCards;
private List<PayMethod> mIps;
//fill Pager/Adapter/List
#Override
public void onPageSelected(int position) {
if () {//If the page comes from mCardsPager
//do Something with mCards
} else { //else the page comes from mIpsPager
//do Something with mIps
}
}
}
You can set different listeners for each ViewPager rather than implement on Activity class.
Like this
mCardsPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i1) {
}
#Override
public void onPageSelected(int i) {
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
AND
mIpsPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i1) {
}
#Override
public void onPageSelected(int i) {
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
Setting same OnPageChangeListener for multiple ViewPager will not work. You need to create a class which implements OnPageChangeListener. In this class add a constructor which takes ViewPager as an input parameter and hold the value in a data member. Finally, use this class for adding OnPageChangeListener

Unable to get visible/live Fragment

I am stuck in this problem.
I want to maintain live instance of Fragment in application context. What I did is
1st Attempt
public class BaseProjectFragmentParent extends BaseProjectFragment {
#Override
public void onResume() {
super.onResume();
App.getInstance().setLiveFragment(this);
}
#Override
public void onPause() {
super.onPause();
App.getInstance().setLiveFragment(null);
}
}
and I extend all fragments by this base class. I expected live instance to be there in Application class.
Problem is in ViewPager, I have two Fragment in ViewPager where both Fragment's onResume() is called and live instance is set the second Fragment. I am working on some common code so I don't want to use getCurrentItem().
Second Attempt
Next I tried to get this Live Fragment by getSupportFragmentManager().getFragments()
isVisible() is true for both Fragments. (Not useful)
isResumed() is true for both Fragments. (Not useful)
You can use
setUserVisibleHint(boolean isVisibleToUser)
In fragments. This flag is set by the OS when a fragment becomes visible:
class MyFragment extends Fragment {
public MyFragment() {
setUserVisibleHint(false) //This is needed because by default its true
}
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser)
//true if fragment is visible
}
}
However this wont get called inside Viewpager. You have to add a listener to the viewpager and then set your active page manually:
viewPager.addOnPageChangeListener(new OnPageChangeListener() {
public void onPageScrollStateChanged(int state) {}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
public void onPageSelected(int position) {
// Check if this is the page you want.
}
});

How to detect when a fragment appears on the screen?

How could some part of my code be aware of Fragment instance become visible on a screen?
The following snippet will explain my question.
public class MyApp extends Application {
public static final String TAG = MyApp.class.getSimpleName();
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
...
#Override
public void onActivityResumed(Activity activity) {
Log.d(TAG, activity.getClass().getSimpleName() + " is on screen");
}
#Override
public void onActivityStopped(Activity activity) {
Log.d(TAG, activity.getClass().getSimpleName() + " is NOT on screen");
}
...
});
}
Here i can track when any activity within my app appears on the screen. Is there any way to extend this approach on Fragments?
Something like
Activity.getFragmentManager().registerFragmentLifecycleCallbacks();
UPD. I know nothing about activities implementations, do they use fragments at all and how do they use them (injection via xml, ViewPager etc.) The only thing I have within my class is an application context. Let's assume Activity and Fragment implementations are black boxes and i am not able to make any changes.
In your fragment, override onHiddenChanged(...) method:
#Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (hidden) {
Log.d(TAG, ((Object) this).getClass().getSimpleName() + " is NOT on screen");
}
else
{
Log.d(TAG, ((Object) this).getClass().getSimpleName() + " is on screen");
}
}
Hope this work for you!
Without touching the Activity or Fragment code and assuming you don't know the tag or layout it is placed in, there is very little that you can do. The best that I can see is that you could get the FragmentManager in ActivityResumed and ActivityStopped callbacks (because here you have an Activity reference) and apply a BackstackChangedListener. This assumes that you use the backstack when changing between fragments.
The issue with what you are asking is that you want lifecycle callbacks for Fragments on the Application level when you have no control over the middle men, the Activities which are already starved for Fragment callbacks. They do most everything through their FragmentManager, and propagate their own lifecycle callbacks down to the Fragments so that the fragments will behave appropriately. The onResume and onPause callbacks in fragments only occur when they are first created or when the Activity experiences those callbacks. There is only one lifecycle callback for Fragments in Activities, onAttachFragment, which if you could override, would give you references to the Fragments that are attached to the Activity. But you said you can't change the Activity or the Fragment, and you want to know when the Fragments are shown.
So if you don't use the backstack, I don't think there's a way to do what you want.
For putting Fragments inside Activity i use SlidingTabLayout which Google uses. Inside it you have ViewPager and some Adapter to populate many Fragments. First of all you have to put this and this files in your project. Then here there is good tutorial for how you can implement SlidingTabLayout.
1) After you have implemented SlidingTabLayout in your Activity, you can detect when and which Fragment becomes visible from Activity:
mSlidingTabLayout.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//Do nothing
}
#Override
public void onPageSelected(int position) {
if (position == 0) {
//Whenever first fragment is visible, do something
} else if (position == 1) {
//Whenever second fragment is visible, do something
} else if (position == 2) {
//Whenever third fragment is visible, do something
} else if (position == 3) {
//Whenever fourth fragment is visible, do something
}
}
#Override
public void onPageScrollStateChanged(int state) {
//Do nothing
}
});
2) You can detect if Fragment is visible from Fragment itself as i answered here, however this may get called before onCreateView() of Fragment, so check answer in the link:
#Override
public void setUserVisibleHint(boolean visible){
super.setUserVisibleHint(visible);
if (visible){
//when this Fragment is active, do something
}
}
3) You can change also change colors of indicators of each Tab like this from Activity:
mSlidingTabLayout.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
#Override
public int getIndicatorColor(int position) {
if (position == 0) {
return getResources().getColor(R.color.orange);
} else if (position == 1) {
return getResources().getColor(R.color.redDimmed);
} else if (position == 2) {
return getResources().getColor(R.color.yellow);
} else if (position == 3) {
return getResources().getColor(R.color.green);
} else {
return getResources().getColor(R.color.redLight);
}
}
#Override
public int getDividerColor(int position) {
return getResources().getColor(R.color.defaultActionBarBg);
}
});
Use same way as activity
set flag in application class to check visiblity of fragment, use below code in fragment
#Override
public void onStart() {
super.onStart();
Log.e( "Fragment is visible", "Fragment is visible");
Application Class.isFragmentShow = true;
}
#Override
public void onPause() {
super.onPause();
Log.e("Fragment is not visible", "Fragment is not visible");
Application Class.isFragmentShow = false;
}
to communicate with fragment you have to call that activity in which fragment added then use below code
MainFragment fragment = (MainFragment) fragmentManager.findFragmentByTag("MainFragment");
fragment.setFilter();
Don't exist a default way to do, but you can make your own Callbacks, I made this and works fine, first need have a BaseFragment class where we'll handle all fragment events.
public class BaseFragment extends Fragment {
private String fragmentName;
private FragmentLifecycleCallbacks listener;
public void registerCallBacks(String fragmentName){
// handle the listener that implement 'MyApp' class
try{
listener = (FragmentLifecycleCallbacks) getActivity().getApplication();
} catch (ClassCastException e) {
throw new ClassCastException("Application class must implement FragmentLifecycleCallbacks");
}
// set the current fragment Name for the log
this.fragmentName = fragmentName;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if(listener!=null) {
listener.onAttachFragment(fragmentName);
}
}
#Override
public void onResume() {
super.onResume();
if(listener!=null) {
listener.onResumeFragment(fragmentName);
}
}
#Override
public void onStop() {
super.onStop();
if(listener!=null) {
listener.onStopFragment(fragmentName);
}
}
// 'MyApp' class needs implement this interface to handle all the fragments events
public interface FragmentLifecycleCallbacks{
void onStopFragment(String fragmentName);
void onResumeFragment(String fragmentName);
void onAttachFragment(String fragmentName);
}}
On 'MyApp' class implement the interface of BaseFragment
public class MyApp extends Application implements BaseFragment.FragmentLifecycleCallbacks{
public static final String TAG = MyApp.class.getSimpleName();
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onStopFragment(String fragmentName) {
Log.d(TAG, fragmentName + " is NOT on screen");
}
#Override
public void onResumeFragment(String fragmentName) {
Log.d(TAG, fragmentName + " is on screen");
}
#Override
public void onAttachFragment(String fragmentName) {
Log.d(TAG, fragmentName + " is attached to screen");
}}
And now each Fragment that you have need extends 'BaseFragment' and register to the global listener
public class FragmentA extends BaseFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_simple, container, false);
// here register to the global listener
registerCallBacks(FragmentA.class.getName());
return rootView;
}}
Hope this helps!
Intercept onWindowFocusChanged() in the activity and propagate that to the interested fragment.
Try this
private Boolean isFragmentVisible()
{
if(getFragmentManager().findFragmentByTag("TAG") != null && getFragmentManager().findFragmentByTag("TAG").isVisible())
{
//The fragment is visible
return true;
}
return false;
}
Alternative way
private Boolean isFragmentVisible()
{
return getFragmentManager().findFragmentByTag("TAG") != null && getFragmentManager().findFragmentByTag("TAG").isVisible();
}
You can know the following with the built in method called "onActivityCreated(Bundle)" this method tells that the fragment has been created thus you get to know that the fragment appears on the screen Click here for reference
Hope it helps
I've looked through what's available without using a base Fragment or Activity class but couldn't find any. I've made an implementation that provides basic (onAdded / onRemoved) functionality for all fragments in your application. It is certainly possible to extend it to report the current state of the fragment (onAttach, onResume, onPause, onDetach, ...).
You can find the code along with a sample here: https://github.com/Nillerr/FragmentLifecycleCallbacks
It works both for non-support library Fragments and support library Fragments through different implementations. The support library class is safer to use and should perform better, because the non-support one uses Reflection to access the fragments, while the support library FragmentManager includes a getFragments() method.
If you are setting a Fragment to your View, you probably have a container where it will be shown. Given that this container is, say, a FrameLayout with id R.id.container, you can do that:
Fragment f = fragmentManager.findFragmentById(R.id.container);
if (f instanceof YourFragment) {
// TODO something when YourFragment is ready
}
Does this interface provide anything helpful to you?
https://github.com/soarcn/AndroidLifecyle/blob/master/lifecycle/src/main/java/com/cocosw/lifecycle/FragmentLifecycleCallbacks.java
It sounds like your best bet if you can't override the Fragment's own onResume() method is to create your own interface that extends ActivityLifecycleCallbacks, then put your logging code in the onFragmentResumed(Fragment yourFragment) method.
You can get a pointer to the Fragment by doing something like this:
int yourFragmentId = 0; //assign your fragment's ID to this variable; Fragment yourFragment.getId();
FragmentManager fm = activity.getFragmentManager();
Fragment f = fm.findFragmentById(yourFragmentId);
whereever u want to check if fragment is visible or not.. just check isMenuVisible() value.
this is fragment's method which i used to check visible fragment when i have to fire some http request from viewpager selected Item.
hope this helps.
in my case i was using this method in onActivityCreated().
In you fragment override method setMenuVisibility If you are using ViewPager and are swiping from left and right, this method is called when the visivility of the fragment gets changed.
Here is a sample from my project
public abstract class DemosCommonFragment extends Fragment {
protected boolean isVisible;
public DemosCommonFragment() {
}
#Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
isVisible = menuVisible;
// !!! Do Something Here !!!
}
}
Animation listener
I have NOT checked all use cases and there is an unhandled exception. You can play around with it to fit your use case. Please feel free to comment your opinions or use cases it did not solve.
NOTE: You can add fragmentWillDisappear and fragmentDidDisappear by handling for enter in onCreateAnimation.
Parent Fragment:
public class BaseFragment extends Fragment {
private Animation.AnimationListener animationListener;
private void setAnimationListener(Animation.AnimationListener animationListener) {
this.animationListener = animationListener;
}
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
fragmentWillAppear(animation);
}
#Override
public void onAnimationEnd(Animation animation) {
fragmentDidAppear(animation);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
#Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
AnimationSet animSet = new AnimationSet(true);
Animation anim = null;
try {
anim = AnimationUtils.loadAnimation(getActivity(), nextAnim);
} catch (Exception error) {
}
if (anim != null) {
anim.setAnimationListener(animationListener);
animSet.addAnimation(anim);
}
return animSet;
}
public void fragmentDidAppear(Animation animation) {
}
public void fragmentWillAppear(Animation animation) {
}
}
Child Fragment:
class ChildFragment extends BaseFragment {
#Override
public void fragmentDidAppear(Animation animation) {
super.fragmentDidAppear(animation);
}
#Override
public void fragmentWillAppear(Animation animation) {
super.fragmentWillAppear(animation);
}
}

Callback for ViewPager transition to next pane?

Is there any way for me to invoke a callback when the user swipes from one pane to the next? As far as my experimentation has revealed, the present (primary) pane/fragment as well as the adjacent two (to the left and right) are all 'resumed', so none of the regular fragment lifecycle callbacks are invoked. I'm interested in this in order to hide a MediaController as soon as the pane it's associated with has been left.
You can attach an OnPageChangeListener to your ViewPager to get updates on when the user swipes to a new page:
viewPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageScrollStateChanged(int state)
{
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
}
#Override
public void onPageSelected(int position)
{
Log.d("MainActivity", "New position = " + position);
}
});
And if you use a FragmentPagerAdapter, your ViewPager's pages will be cached in memory. If you use a FragmentStatePagerAdapter, they will not be cached.
the Fragment's setUserVisibleHint() would be callback as long as a fragment was completely disappeared or appeared, hide or show the MediaController operation can be done here.
public class YourFragment extend android.support.v4.app.Fragment {
...
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
System.out.println("VISIBLE");
} else {
System.out.println("GONE");
}
}
...
}

multiple layout viewpager with one fragment

I must clear that I am looking for an example or answer where I can use various differnt layout designs in a viewpager and the data in all the pages would be dynamic and all pages can be interacted by the user.
My Use Case and current approach towards the problem :
So I have got 8 different types of question types and so I have created layouts for all of them. Also I the data in the views for these layouts has to be populated via java Map that has fetched data from the sqlite DB.
But a test may contain 25 questions with different layouts out of the above 8. And for all these 25 questions I want to use a Viewpager and a Fragment that will return the required layout based on the passed question type value out of my java map.
My apporach towards this :
I have created an activity and have inflated it with a viewpager layout :
R.layout.practice_pager
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/test_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
*Activity Edited code *
public class TestActivity extends FragmentData implements FragmentData{
FragmentManager manager=getSupportFragmentManager();
private ViewPager mViewPager;
private MyFragmentPagerAdapter mMyFragmentPagerAdapter;
int PAGE_COUNT = 0;
GrePracticeTestRecord p=new GrePracticeTestRecord();
private HashMap<Integer, GrePracticeResultRecord> mPracResultMap;
public static int fragmentToReturn=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.practice_pager);
mViewPager = (ViewPager) findViewById(R.id.test_container);
//This function is called to fetch the data from sqlite db and fill the map with data
LoadingTestView();
PAGE_COUNT=mPracRecordMap.size();
initPager();
}
//here I initialize the pager and set the adapter to it
public void initPager()
{
p.setQUES(mPracRecordMap.get(1).getQUES());
p.setEXPL(mPracRecordMap.get(1).getEXPL());
fragmentToReturn=Integer.parseInt(mPracRecordMap.get(1).getQTYPE());
setData(p);
mMyFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(),fList);
mViewPager.setAdapter(mMyFragmentPagerAdapter);
mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int arg0) {
mMyFragmentPagerAdapter.notifyDataSetChanged();
p.setQUES(mPracRecordMap.get(mViewPager.getCurrentItem()+1).getQUES());
p.setEXPL(mPracRecordMap.get(mViewPager.getCurrentItem()+1).getEXPL());
setData(p);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
#Override
public void setData(GrePracticeTestRecord p) {
// TODO Auto-generated method stub
}
#Override
public GrePracticeTestRecord getData() {
// TODO Auto-generated method stub
return p;
}
}
My Adapter Edited code
public class MyFragmentPagerAdapter extends FragmentStatePagerAdapter{
private List<Fragment> fragments;
public MyFragmentPagerAdapter(FragmentManager fm,List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
/** This method will be invoked when a page is requested to create */
#Override
public Fragment getItem(int position) {
System.out.println("value of position "+position);
return this.fragments.get(position);
}
/** Returns the number of pages */
#Override
public int getCount() {
return this.fragments.size();
}
#Override
public int getItemPosition(Object object) {
// TODO Auto-generated method stub
return MyFragmentPagerAdapter.POSITION_NONE;
}
}
Interface FragmentData
public interface FragmentData {
public void setData(GrePracticeTestRecord p);
public GrePracticeTestRecord getData();
}
TestFragment Edited code
public class TestFragment extends Fragment {
AnswerEnterListener callBack;
FragmentData fD;
Button submitAnswer;
EditText userAnswer;
TextView qText,expl;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.qtype1, container, false);
}
public interface AnswerEnterListener
{
public void onInputAnswer(String ans);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
callBack=(AnswerEnterListener) activity;
fD=(FragmentData) activity;
} catch (Exception e) {
// TODO: handle exception
}
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
qText=(TextView) getActivity().findViewById(R.id.question_text);
expl=(TextView)getActivity().findViewById(R.id.explanation_text);
qText.setText(Html.fromHtml(fD.getData().getQUES()));
expl.setText(Html.fromHtml(fD.getData().getEXPL()));
}
}
Similar to TestFragment , I have not the other fragments too. Each for a layout type.
Issues :
The first layout is repeated two times at the first time , and also when I swipe back then the position of data is misplaced.
Is this the right approach, I have been suggested by someone that you should use three fragments and update the left and right fragments with data , but this actually bounced off me. Can anyone share a good example of it or a blog.
I must clear that I am looking for an example or answer where I can
use various differnt layout designs in a viewpager and the data in all
the pages would be dynamic and all pages can be interacted by the
user.
This should be quite easy to make but you seem to have complicated this a lot. You need to do something like this:
Get the data from the database with the LoadingTestView(); function.
Initialize the ViewPager and set it's adapter. The adapter will return the proper fragment instance in the getItem() method, based on whatever criteria you have.
In the fragments, retrieve the data from the activity which should expose the data through some method.
I've made a simple example that you can find here.

Categories

Resources