ViewPager.setOffscreenPageLimit(0)无法按预期工作

时间:2012-04-09 12:32:10

标签: android android-viewpager android-support-library

我在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个屏幕外页面,或者我在这里做错了什么?

13 个答案:

答案 0 :(得分:118)

我找到的最佳方式是setUserVisibleHint
将此添加到您的片段

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

答案 1 :(得分:108)

  

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

是。如果我正确地阅读源代码,您应该在LogCat中收到关于此的警告,例如:

Requested offscreen page limit 0 too small; defaulting to 1

答案 2 :(得分:7)

您可以尝试这样:



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

答案 3 :(得分: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{
     }
}

答案 4 :(得分:1)

ViewPager默认加载下一页(片段),您无法通过setOffscreenPageLimit(0)进行更改。但你可以做点什么来破解。 您可以在包含ViewPager的Activity中实现onPageSelected函数。在下一个片段(你不想加载)中,你编写了一个函数,让我们说showViewContent()你放入所有资源消耗的初始化代码,并且在onResume()方法之前什么也不做。然后在onPageSelected中调用showViewContent()函数。希望这会有所帮助。

答案 5 :(得分: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);
}

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

答案 6 :(得分:0)

对于“instantiateItem”函数,只需准备片段,但不要加载繁重的内容。

使用“onPageChangeListener”,这样每次进入特定页面时,都会加载其重要内容并显示它。

答案 7 :(得分:0)

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

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

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

快乐的编码...

答案 8 :(得分:0)

我有同样的问题。我在这个网站上找到了一些有用的代码并对其进行了转换。

mViewPager.setOffscreenPageLimit(...)的min int;是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.如果需要,可以添加其他页面。 在我的情况下,我需要用户在生成另一个之前先处理当前页面。他这样做,然后,没有问题可以刷到下一页。

希望对某人有所帮助。

答案 9 :(得分: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;
    }
} 

答案 10 :(得分:0)

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

loopy

答案 11 :(得分:0)

仅使用一页查看寻呼机:

这是 2021 年 - 2 月,Alhamdulillah,我只能使用 viewPager 添加一页。方法是:ViewPagerFragmentPagerAdapterTablayoutfragment。就我而言,我可以用多个 Pages 填充多个 tabs,或者只用一个 Page 填充一个 Tab。当一个选项卡和一页,向左或向右滑动时,我可以设法更改我的文档的章节(我想接下来显示)。当有很多页面和很多标签时,我可以更改整个文档集。

在主 Activity Oncreate 中:(这是我的工作代码方法,我的工作代码在这里没有任何更改):

if(getIntent()!=null){
            if(getIntent().getStringExtra("ONLY_TAFHEEM")!=null)
             sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager(), suraName, suraId, ayatId, true);
            else
            sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager(), suraName, suraId, ayatId, false);
        }else {
            sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager(), suraName, suraId, ayatId, false);
        }

        final ViewPager viewPager = findViewById(R.id.view_pager);
        viewPager.setAdapter(sectionsPagerAdapter);
        tabsLayout = findViewById(R.id.tabs);
        tabsLayout.animate();

        tabsLayout.setupWithViewPager(viewPager);

在适配器中:

 @NonNull
    @Override
    public Fragment getItem(int position) {

          
    // getItem is called to instantiate the fragment for the given page.
    // Return a PlaceholderFragment (defined as a static inner class below).
    return PlaceholderFragment.sendData(mContext, postion, suraName, suraId, ayahId, ARABIC_AYAH, BENGALI_AYAH, actualDbNames[position], tafsirDisplayNames[position]);
}


@Nullable
@Override
public CharSequence getPageTitle(int position) {
   
    return tafsirDisplayNames[position];
}

@Override
public int getCount() {
   // this is the tricky part // Show pages according to array length. // this may only one // this is the tricky part : 
    return tafsirDisplayNames.length;
}

最后是片段公共构造函数:

 public static PlaceholderFragment sendData(Context mContext, int tabIndex, String suraName, String suraId, String ayahNumber, String arabicAyah, String bengaliAyah, String actualDbName, String displayDbName) {

        Log.i("PlaceHolder", "Tafhim sendData: " + bengaliAyah);
        PlaceholderFragment fragment = new PlaceholderFragment();
        Bundle bundle = new Bundle();
        mContext_ = mContext;
        BENGALI_AYAH = bengaliAyah;
        _DISPLAY_DB_NAME = displayDbName;
        bundle.putInt(ARG_SECTION_NUMBER, tabIndex);
        bundle.putString(SURA_NAME, suraName);
        bundle.putString(SURA_ID, suraId);
        bundle.putString(AYAH_NUMBER, ayahNumber);
        bundle.putString(ARABIC_AYAH, arabicAyah);
        bundle.putString(ACTUAL_DB_NAME, actualDbName);
        bundle.putString(DISPLAY_DB_NAME, displayDbName);
        fragment.setArguments(bundle);
        return fragment;
    }

就是这样,只需将数组(选项卡标签)传递给适配器,(它可能只有一个元素,以防万一,一页),根据我的需要,我可以填充一页或多页,并根据它填充一个或多个选项卡:在上面的代码中,数组是:tafsirDisplayNames。我也可以在适配器中手动创建数组,当适配器第一次调用时,或者,在重新创建 MainActivity 时使用 +-元素重新创建数组。

多数民众赞成,Alhamdulillah,快乐编码.......

答案 12 :(得分:0)

// step 1: add  BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT FragmentPagerAdapter contractor
   
    public class BottomTabViewPager extends FragmentPagerAdapter {
    
        private final List<Fragment> mFragmentList = new ArrayList<>();
        private final List<String> mFragmentTitleList = new ArrayList<>();
    
        public BottomTabViewPager(FragmentManager manager) {
            super(manager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
    
        }
    
        @Override
        public Fragment getItem(int position) {
            return mFragmentList.get(position);
        }
    
        @Override
        public int getCount() {
            return mFragmentList.size();
        }
    
        public void addFragment(Fragment fragment, String title) {
            mFragmentList.add(fragment);
            mFragmentTitleList.add(title);
        }
    
        public void addTabs(String title) {
    
            mFragmentTitleList.add(title);
        }
    
    
        @Override
        public CharSequence getPageTitle(int position) {
            return mFragmentTitleList.get(position);
            // return null;
        }
    }
    
    
   // step  2:  You can try like this :

    
    public class MyFragment extends Fragment  {
    
       
    
        public MyFragment() {
            // Required empty public constructor
        }
    
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            View view = inflater.inflate(R.layout.fragment_ui, container, false);
            
            return view;
        }
    
     @Override
        public void onResume() {
            super.onResume();
            /**
             * Load your stuffs here.
             */
        }
    
      }