java ViewPager.setOffscreenPageLimit(0) 根本没有效果。如何在 ViewPager 中一次只加载一个页面?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17948681/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 19:42:13  来源:igfitidea点击:

ViewPager.setOffscreenPageLimit(0) has no effect at all. How do I only load one page at a time in a ViewPager?

javaandroidandroid-viewpager

提问by code511788465541441

even when I set oViewPager.setOffscreenPageLimit(0) my view pager still loads 1 off screen page on each side of the visible page.

即使我设置 oViewPager.setOffscreenPageLimit(0) 我的视图寻呼机仍然在可见页面的每一侧加载 1 个离屏页面。

How do I make it only load the page when the user slides to it?

如何让它只在用户滑动到页面时加载页面?

My adapter if it helps:

我的适配器是否有帮助:

public class MainPagerAdapter extends FragmentPagerAdapter {
    protected static final String[] CONTENT = new String[] { "page 1", "page 2", "page 3", "page 4", };

    private int mCount = CONTENT.length;

    public MainPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        //return TestFragment.newInstance(CONTENT[position % CONTENT.length]);
        return MainFragment.newInstance(position);
    }

    @Override
    public int getCount() {
        return mCount;
    }

    @Override
    public CharSequence getPageTitle(int position) {
      return MainPagerAdapter.CONTENT[position % CONTENT.length];
    }

    public void setCount(int count) {
        if (count > 0 && count <= 10) {
            mCount = count;
            notifyDataSetChanged();
        }
    }


}

回答by edthethird

Another alternative is to use a OnPageChangeListener, and whenever a page change occurs call a refresh method in your fragments.

另一种选择是使用OnPageChangeListener, 并且每当发生页面更改时调用片段中的刷新方法。

This will require you to set a higher OffScreenPageLimit, but the fragments will be updated every time one is brought into view.

这将需要您设置更高的OffScreenPageLimit,但是每次看到片段时都会更新片段。

pager.setOnPageChangeListener(new OnPageChangeListener() {

     @Override
     public void onPageSelected(int position){
         ((MyRefreshableFragment)pager.getAdapter().getItem(position)).refresh();
     }

     @Override
     public void onPageScrolled(int arg0, float arg1, int arg2) {}
     @Override
     public void onPageScrollStateChanged(int arg0) {}
  });

回答by CommonsWare

How do I make it only load the page when the user slides to it?

如何让它只在用户滑动到页面时加载页面?

Write your own ViewPager. As is noted by Jani's answer, ViewPagerhas a minimum offscreen page limit of 1 to each side.

自己写ViewPager。正如 Jani 的回答所指出的,ViewPager每边的最小屏幕外页面限制为 1。

This is required for the swiping animation to work smoothly. Otherwise, if we had to wait for you to set up the UI for the next page, the user's swipe would be frozen, or swipe to blank content, for however long it takes you to get that UI established.

这是滑动动画顺利工作所必需的。否则,如果我们不得不等待您为下一页设置 UI,则用户的滑动将被冻结,或者滑动到空白内容,无论您需要多长时间才能建立该 UI。

回答by Keshav Gera

add this method in fragment

在片段中添加此方法

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
        // load data here      resumePlayer(); 
    }else{
       // fragment is no longer visible    pausePlayer();
    }
}

回答by Random Guy

I know this is very late answer but for God's sake you do not have to write your own viewpager as someone suggested.

我知道这是一个很晚的答案,但看在上帝的份上,您不必像有人建议的那样编写自己的 viewpager。

Lets take things from start:

让我们从头开始:

How viewpager works:

查看页面的工作原理:

By default it keeps one item in memory either side so it does not have to create it everytime.

默认情况下,它在内存的任一侧保留一个项目,因此不必每次都创建它。

1st Solution:

第一个解决方案:

mViewPager.setOffscreenPageLimit(0);

which results to:

结果是:

Requested offscreen page limit 0 too small; defaulting to 1

请求的屏幕外页面限制 0 太小;默认为 1

2nd Solution:

第二种解决方案:

You want to update the Fragment when it is actually visible to the user so use the method:

您想在用户实际可见时更新 Fragment,因此请使用以下方法:

@Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
           //Do something like 
           //adapter.notifyDataSetChanged();
        }
    }

Hope it helps someone in the future!!!

希望对未来的人有所帮助!!!

回答by Dante

I use a Loaderand init the loaders of each fragment in the onPageSelected.

我使用Loader并初始化onPageSelected.

回答by Jani Bela

You cant do this. You will get an error like: "Requested offscreen page limit 0 too small; defaulting to 1". But here you can find more about it: ViewPager.setOffscreenPageLimit(0) doesn't work as expected

你不能这样做。您将收到如下错误:“请求的屏幕外页面限制 0 太小;默认为 1”。但在这里你可以找到更多关于它的信息:ViewPager.setOffscreenPageLimit(0) 不按预期工作

回答by Yuhan Zhang

there are the source code

有源代码

   /**
 * Set the number of pages that should be retained to either side of the
 * current page in the view hierarchy in an idle state. Pages beyond this
 * limit will be recreated from the adapter when needed.
 *
 * <p>This is offered as an optimization. If you know in advance the number
 * of pages you will need to support or have lazy-loading mechanisms in place
 * on your pages, tweaking this setting can have benefits in perceived smoothness
 * of paging animations and interaction. If you have a small number of pages (3-4)
 * that you can keep active all at once, less time will be spent in layout for
 * newly created view subtrees as the user pages back and forth.</p>
 *
 * <p>You should keep this limit low, especially if your pages have complex layouts.
 * This setting defaults to 1.</p>
 *
 * @param limit How many pages will be kept offscreen in an idle state.
 */
public void setOffscreenPageLimit(int limit) {
    if (limit < DEFAULT_OFFSCREEN_PAGES) {//DEFAULT_OFFSCREEN_PAGES = 1
        Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +
                DEFAULT_OFFSCREEN_PAGES);
        limit = DEFAULT_OFFSCREEN_PAGES;
    }
    if (limit != mOffscreenPageLimit) {
        mOffscreenPageLimit = limit;
        populate();
    }
}

you can custom your viewpager by copy the viewpager's source, then change this method

您可以通过复制 viewpager 的源来自定义您的 viewpager,然后更改此方法

like this

像这样

public class LazyViewPager extends ViewGroup {
private static final String TAG = "LazyViewPager";
private static final boolean DEBUG = false;

private static final boolean USE_CACHE = false;

private static final int DEFAULT_OFFSCREEN_PAGES = 0;//change default to load one page,no offset,ViewPager is 1,so cache 2 Fragment
private static final int MAX_SETTLE_DURATION = 600; // ms

回答by Dulanga

I found a solution for this after few work round. This is work perfectly. each tab fragment class implement this code steps.

经过几次工作后,我找到了解决方案。这是完美的工作。每个选项卡片段类实现此代码步骤。

 private boolean loadData = false;

 @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (this.isVisible() && isVisibleToUser ) {
            loadData = true;
            // Load your data or call web services 
            performDataRequestAsyncTask();
        }
    }

and In onCreateView Load same data or call same web service like below

并在 onCreateView 加载相同的数据或调用相同的 Web 服务,如下所示

     if(!loadData && YourMainFragment.yourMainFragment.getCurrentTab() == CURRENT_TAB_INDEX){
           // Load your data or call web services 
        performDataRequestAsyncTask();
      }

In YourMainFragment which you initialize your viewrpage add this method to get currentTab

在您初始化视图页面的 YourMainFragment 中,添加此方法以获取 currentTab

public int getCurrentTab(){
        if(mViewPager != null) return mViewPager.getCurrentItem();
        else return -1;
    }