Access ViewPager Fragment method from Activity
This is my scenario:
I have ViewPager in my Activity which hosts 6 Fragment. I disabled paging by swiping with finger, so whenever I want to swipe I use related button and :
viewPager.setCurrentItem(viewPager.getCurrentItem() + 1, true);
In each fragment that is swiped (after swipe is finished) I want to send a GET request to my server and fetch some data and show it in that fragment. for doing that:
First Approach : I used this code in my fragments which runs as soon as fragment become visible:
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser)
{
sendGetRequest();
}
}
But , here was a problem : that setUserVisibleHint executes exactly whene the fragment visible , and because of that the animation of swiping came with some lag(it wasn't smooth enough).
So I used Second Approach :
I added an OnPageChangeListener() to ViewPager in hosted activity like this :
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
int CurrentPossition = 0;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }
@Override
public void onPageSelected(int position) {
CurrentPossition = position;
}
@Override
public void onPageScrollStateChanged(int state) {
if(state == ViewPager.SCROLL_STATE_IDLE && CurrentPossition != 0){
Toast.makeText(getBaseContext(),"finished" , Toast.LENGTH_SHORT).show();
try{
new fragment_two().sendGetRequest();;
}catch(Exception ex){
ex.printStackTrace();
}
}
}
});
It works great, and toast shows as soon as swipe finished, but unlike fragment which visible completely , when sendGetRequest() runs i get NullPointerException.
here is StackTrace :
04-08 20:15:37.840 12848-12848/com.example.mohamad.travelagency W/System.err: java.lang.NullPointerException
04-08 20:15:37.850 12848-12848/com.example.mohamad.travelagency W/System.err: at android.content.ContextWrapper.getApplicationInfo(ContextWrapper.java:152)
04-08 20:15:37.850 12848-12848/com.example.mohamad.travelagency W/System.err: at android.view.ContextThemeWrapper.getTheme(ContextThemeWrapper.java:103)
04-08 20:15:37.850 12848-12848/com.example.mohamad.travelagency W/System.err: at android.app.AlertDialog.resolveDialogTheme(AlertDialog.java:143)
04-08 20:15:37.850 12848-12848/com.example.mohamad.travelagency W/System.err: at android.app.AlertDialog.<init>(AlertDialog.java:98)
04-08 20:15:37.850 12848-12848/com.example.mohamad.travelagency W/System.err: at android.app.ProgressDialog.<init>(ProgressDialog.java:77)
04-08 20:15:37.850 12848-12848/com.example.mohamad.travelagency W/System.err: at com.example.mohamad.travelagency.fragment_two.GetServetData_L1(fragment_two.java:458)
04-08 20:15:37.850 12848-12848/com.example.mohamad.travelagency W/System.err: at com.example.mohamad.travelagency.MainActivity$1.onPageScrollStateChanged(MainActivity.java:124)
04-08 20:15:37.860 12848-12848/com.example.mohamad.travelagency W/System.err: at android.support.v4.view.ViewPager.dispatchOnScrollStateChanged(ViewPager.java:1811)
04-08 20:15:37.860 12848-12848/com.example.mohamad.travelagency W/System.err: at android.support.v4.view.ViewPager.setScrollState(ViewPager.java:404)
04-08 20:15:37.860 12848-12848/com.example.mohamad.travelagency W/System.err: at android.support.v4.view.ViewPager.access$000(ViewPager.java:91)
04-08 20:15:37.860 12848-12848/com.example.mohamad.travelagency W/System.err: at android.support.v4.view.ViewPager$3.run(ViewPager.java:250)
04-08 20:15:37.860 12848-12848/com.example.mohamad.travelagency W/System.err: at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
04-08 20:15:37.860 12848-12848/com.example.mohamad.travelagency W/System.err: at android.view.Choreographer.doCallbacks(Choreographer.java:574)
04-08 20:15:37.860 12848-12848/com.example.mohamad.travelagency W/System.err: at android.view.Choreographer.doFrame(Choreographer.java:543)
04-08 20:15:37.860 12848-12848/com.example.mohamad.travelagency W/System.err: at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
04-08 20:15:37.860 12848-12848/com.example.mohamad.travelagency W/System.err: at android.os.Handler.handleCallback(Handler.java:733)
04-08 20:15:37.860 12848-12848/com.example.mohamad.travelagency W/System.err: at android.os.Handler.dispatchMessage(Handler.java:95)
04-08 20:15:37.860 12848-12848/com.example.mohamad.travelagency W/System.err: at android.os.Looper.loop(Looper.java:136)
04-08 20:15:37.870 12848-12848/com.example.mohamad.travelagency W/System.err: at android.app.ActivityThread.main(ActivityThread.java:5271)
04-08 20:15:37.870 12848-12848/com.example.mohamad.travelagency W/System.err: at java.lang.reflect.Method.invokeNative(Native Method)
04-08 20:15:37.870 12848-12848/com.example.mohamad.travelagency W/System.err: at java.lang.reflect.Method.invoke(Method.java:515)
04-08 20:15:37.870 12848-12848/com.example.mohamad.travelagency W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:851)
04-08 20:15:37.870 12848-12848/com.example.mohamad.travelagency W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:667)
04-08 20:15:37.870 12848-12848/com.example.mohamad.travelagency W/System.err: at dalvik.system.NativeStart.main(Native Method)
any idea would be great. best regards
Answer :
Daniel Nugent's code worked well , beside for showing ProgressDialog during sending GET request i used :
final ProgressDialog dialog = new ProgressDialog(new MainActivity());
this code returned NullPointerException too , i removed it and now working well.
Solution 1:
Using the ViewPager.OnPageChangeListener
is the correct way to go, but you will need to refactor your adapter a bit in order to keep a reference to each Fragment contained in the FragmentPagerAdapter.
You do that using the instantiateItem()
method override in the adapter, here is a simplified example:
class PagerAdapter extends FragmentPagerAdapter {
String tabTitles[] = new String[] { "One", "Two", "Three", "Four"};
Context context;
//This will contain your Fragment references:
public Fragment[] fragments = new Fragment[tabTitles.length];
public PagerAdapter(FragmentManager fm, Context context) {
super(fm);
this.context = context;
}
@Override
public int getCount() {
return tabTitles.length;
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new FragmentOne();
case 1:
return new FragmentTwo();
case 2:
return new FragmentThree();
case 3:
return new FragmentFour();
}
return null;
}
//This populates your Fragment reference array:
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
fragments[position] = createdFragment;
return createdFragment;
}
@Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
return tabTitles[position];
}
}
Then, instead of creating a new Fragment, use the one contained in the adapter:
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }
@Override
public void onPageSelected(int position) {
// do this instead, assuming your adapter reference
// is named mAdapter:
Fragment frag = mAdapter.fragments[position];
if (frag != null && frag instanceof FragmentTwo) {
((FragmentTwo)frag).sendGetRequest();
}
}
@Override
public void onPageScrollStateChanged(int state) { }
});
Note that if you're using different Fragment classes in your adapter, you can implement an interface that defines sendGetRequest()
, and in each of your Fragment classes implement the sendGetRequest() method.
If you don't go with the interface approach, you will need to cast the Fragment to your own Fragment type as shown in the example above, i.e.:
if (frag instanceof FragmentTwo) {
((FragmentTwo)frag).sendGetRequest();
}
UPDATE
For using ViewPager2 and Kotlin, here is how it would look:
viewPager.registerOnPageChangeCallback(
object: ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
val frag: Fragment = mAdapter.fragments[position]
if (frag != null && frag is FragmentTwo) {
(frag as FragmentTwo).sendGetRequest()
}
}
}
)