ViewPager.setOffscreenPageLimit(0)不能按预期工作


100

我在ViewPager实例中使用的片段占用大量资源,因此我只想一次加载一个。当我尝试以下操作时:

mViewPager.setOffscreenPageLimit(0);
mViewPager.setAdapter(mPagerAdapter);

我的FragmentStatePagerAdapter.getItem(int position)覆盖函数被调用了3次,这是我调用时发生的情况mViewPager.setOffscreenPageLimit(1)。我希望它只被调用一次,因为我指定了0个屏幕外页面。

我相信我会正确地调用所有内容,因为如果调用mViewPager.setOffscreenPageLimit(2),它会FragmentStatePagerAdapter.getItem(int position)被调用5次,正如我期望的那样。

ViewPager是否至少需要1个离屏页面,或者我在这里做错了什么?


9
我添加了一个功能请求:code.google.com/p/android/issues/detail?id=56667
标记


我只有3个标签,设置ViewPager.setOffscreenPageLimit(2)对我有用。试试ViewPager.setOffscreenPageLimit(totTabs - 1)
sibin

Answers:


112

ViewPager是否至少需要1个离屏页面

是。如果我正确阅读了源代码,则应该在LogCat中收到有关此警告,例如:

Requested offscreen page limit 0 too small; defaulting to 1

6
这不是解决方案!我只想加载1个片段而不是2个。肯定有可能吗?
HGPB 2013年

14
@哈拉尔多:“肯定有可能吗?” -不能ViewPagerViewPager创建这些片段以使视图存在,以便用户在它们之间滑动,动画效果显示旧视图从屏幕上滑出,新视图滑动到屏幕上。欢迎您尝试编写自己的ViewPager可以在不存在的事物之间滑动的内容。您可以在code.google.com/p/android/issues/detail?id=56667#c3
CommonsWare 2013年

2
是的,我已经阅读了此问题。只是不合逻辑。我希望能够setOffscreenPageLimit(0)为0。然后我自己应对后果。例如,默认的空片段可以是占位符,直到某个片段已加载。所有这些都可以在UI线程之外进行。无论如何,我没有考虑太多。
HGPB 2013年

5
@Haraldo:“例如,默认的空片段可以是占位符,直到加载了一个片段为止” –欢迎您使用现有的实现在您的片段中保留一个占位符,ViewPager在可用时将其替换为实际内容。
CommonsWare 2013年

2
onPageChangeListener似乎是解决方案。
alicanbatur

123

我发现的最好方法是setUserVisibleHint将此
添加到您的片段

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

1
+++++用于此解决方案!!!谢谢,添加此代码后,我第一次获得了NPL,我刚刚添加了try catch块,它对我来说非常完美!!!
Bhavin Chauhan

1
使用此功能时,它不会在secondViewPager片段上加载日期,而在第二个片段上,它会加载第三个片段的数据。有人可以帮我吗?
Arshad

我错过了什么吗,setUserVisibleHint在onCreateView之前调用
Anton

最好的解决方案现已弃用
M.Sameer

@ M.Sameer setUserVisibleHint的任何替代方法已取消?
Yudi karma

8

您可以这样尝试:

public abstract class LazyFragment extends Fragment {
    protected boolean isVisible;
    /**
     * 在这里实现Fragment数据的缓加载.
     * @param isVisibleToUser
     */
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if(getUserVisibleHint()) {
            isVisible = true;
            onVisible();
        } else {
            isVisible = false;
            onInvisible();
        }
    }
    protected void onVisible(){
        lazyLoad();
    }
    protected abstract void lazyLoad();
    protected void onInvisible(){}

protected abstract void lazyLoad();
protected void onInvisible(){}

最好的答案!
Radesh

7

首先添加

   boolean isFragmentLoaded = false;

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser && !isFragmentLoaded) {
        //Load Your Data Here like.... new GetContacts().execute();

        isFragmentLoaded = true;
    }
else{
     }
}

6
但是此方法在onCreateView之前调用
Zar E Ahmer '16

2

默认情况下,ViewPager会加载setOffscreenPageLimit(0)无法更改的下一页(片段)。但是您可以采取一些措施。您可以在包含ViewPager的Activity中实现onPageSelected函数。在下一个Fragment(您不想加载的片段)中,您编写了一个函数,让我们说showViewContent(),您将所有消耗资源的初始化代码放入其中,并且在onResume()方法之前不执行任何操作。然后在onPageSelected内部调用showViewContent()函数。希望这会有所帮助。


1

这可能是旧线程,但这似乎对我有用。覆盖此功能:

@Override
public void setMenuVisibility(boolean menuVisible) { 
    super.setMenuVisibility(menuVisible);

    if ( menuVisible ) {
        /**
         * Load your stuffs here.
         */
    } else  { 
        /**
         * Fragment not currently Visible.
         */
    } 
}

快乐的编码...


在webview上有什么?我建议您为此创建一个新线程。
ralphgabb15年

1

就我而言,我想在视图中开始一些动画,但是使用setUserVisibleHint遇到了一些问题...
我的解决方案是:

1 /您的适配器的addOnPageChangeListener:

mViewPager.addOnPageChangeListener(this);

2 /实现OnPageChangeListener:

public class PagesFragment extends Fragment implements ViewPager.OnPageChangeListener

3 /覆盖3种方法:

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{

}

@Override
public void onPageSelected(int position)
{ 
}

@Override
public void onPageScrollStateChanged(int state)
{
}

4 /在类上声明并初始化此变量

private static int mTabState = 1;

注意:我的适配器中有三个片段,并将mTabState用于setCurrentItem和适配器的当前位置,以识别哪个片段及时显示给用户... 5 / onPageSelected方法中添加以下代码:

if (mTabState == 0 || position == 0)
    {
        Intent intent = new Intent("animation");
        intent.putExtra("current_position", position);
        LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
    }

如果上一页或当前页是页面0(片段在位置0),则执行此操作

6 /现在在您的片段类中(在适配器位置0的片段中),您必须创建广播接收器并在onResume方法中注册它,然后在onPause方法上注销它:

BroadcastReceiver broadcastReceiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        if (Objects.equals(intent.getAction(), "animation"))
        {
            int currentPosition = intent.getIntExtra("current_position", 0);
            if (currentPosition == 0)
            {
                startAnimation();
                setViewsVisible();
            } else
            {
                setViewsInvisible();
            }
        }
    }
};

@Override
public void onResume()
{
    super.onResume();
    LocalBroadcastManager.getInstance(mContext).registerReceiver(broadcastReceiver, new IntentFilter("animation"));
}

@Override
public void onPause()
{
    super.onPause();
    LocalBroadcastManager.getInstance(mContext).unregisterReceiver(broadcastReceiver);
}

摘要:我有Fragment Pager Adapter巫婆在其中显示了三个片段,我想在Adapter位置0的Fragment中的视图上显示一些动画,为此,我使用BroadcastReceiver。拾取片段后,我将启动“动画”方法并向用户显示视图,而当片段未向用户显示时,我将尝试不可见视图...


1

请尝试使用此代码来解决Viewpager中刷新视图的问题。

/* DO NOT FORGET! The ViewPager requires at least “1” minimum OffscreenPageLimit */
int limit = (mAdapter.getCount() > 1 ? mAdapter.getCount() - 1 : 1);
mViewPager.setOffscreenPageLimit(limit);

0

对于“ instantiateItem”功能,只需准备片段,但不要加载大量内容。

使用“ onPageChangeListener”,以便每次访问特定页面时,都加载并显示其大量内容。


0

我有点同样的问题。我在此站点上找到了一些有用的代码并将其转换。

mViewPager.setOffscreenPageLimit(...)的最小整数 为1,因此即使将其更改为0,您仍将加载2页。

首先要做的是创建一个静态int,我们将调用maxPageCount并重写FragmentStatePagerAdapter方法getCount()来返回maxPageCount:

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

然后创建一个静态方法,该方法可从程序中的任何位置访问,从而可以更改此maxCount:

public static void addPage(){
    maxPageCount++; //or maxPageCount = fragmentPosition+2
    mFragmentStatePagerAdapter.notifyDataSetChanged(); //notifyDataSetChanged is important here.
}

现在将maxPageCount初始化为1。任何时候您都可以添加另一个页面。就我而言,当我需要用户首先处理当前页面,然后再生成另一个页面时。他执行此操作,然后可以毫无问题地滑动到下一页。

希望它能帮助某人。


0

使用此//创建用于获取数据的布尔值私有布尔值isViewShown = false;

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (getView() != null) {
        isViewShown = true;
        // fetchdata() contains logic to show data when page is selected mostly asynctask to fill the data
        fetchData();
    } else {
        isViewShown = false;
    }
} 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.