从Activity访问ViewPager Fragment方法

这是我的场景:

我的 Activity 中有 ViewPager,它承载 6 个 Fragment.我用手指滑动禁用了分页,所以每当我想滑动时,我都会使用相关按钮:

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);

在每个被刷过的片段中(刷完之后)我想向我的服务器发送一个 GET 请求并获取一些数据并在那个片段中显示它.为此:

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();
        }
}

但是,这里有一个问题:setUserVisibleHint 恰好在片段可见时执行,因此滑动动画会出现一些延迟(不够流畅).

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).

所以我使用了第二种方法:我在这样的托管活动中向 ViewPager 添加了 OnPageChangeListener():

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();
                    }
                }
            }
        });

效果很好,滑动完成后吐司显示,但与完全可见的片段不同,当 sendGetRequest() 运行时,我得到 NullPointerException.

It works great, and toast shows as soon as swipe finished, but unlike fragment which visible completely , when sendGetRequest() runs i get NullPointerException.

这里是 StackTrace:

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

回答:Daniel Nugent 的代码运行良好,除了在发送我使用的 GET 请求期间显示 ProgressDialog:

Answer : Daniel Nugent's code worked well , beside for showing ProgressDialog during sending GET request i used :

final ProgressDialog dialog = new ProgressDialog(new MainActivity());

这段代码也返回了 NullPointerException,我删除了它,现在运行良好.

this code returned NullPointerException too , i removed it and now working well.

推荐答案

使用 ViewPager.OnPageChangeListener 是正确的方法,但您需要稍微重构您的适配器以保持对 FragmentPagerAdapter 中包含的每个 Fragment 的引用.

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.

您可以使用适配器中的 instantiateItem() 方法覆盖,这是一个简化的示例:

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];
        }         
 }

然后,不要创建新的 Fragment,而是使用适配器中包含的 Fragment:

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) {  }
});

请注意,如果您在适配器中使用不同的 Fragment 类,则可以实现定义 sendGetRequest() 的接口,并在每个 Fragment 类中实现 sendGetRequest() 方法.

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.

如果您不使用接口方法,则需要将 Fragment 转换为您自己的 Fragment 类型,如上例所示,即:

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();
}

更新

对于使用 ViewPager2 和 Kotlin,它的外观如下:

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()
                    }
                }
            }
    )

相关文章