如何让我的ViewPager一次只加载一个页面,即setOffscreenPageLimit(0);

时间:2013-09-30 14:31:42

标签: android android-viewpager

我理解我可以给setOffscreenPageLimit(int)的最小数字是1.但我需要一次加载一页因为内存问题。

我是否必须使用旧式tabhost等?或者有没有办法/黑客我可以让我的viewPager一次加载一页?

我的适配器使用ViewHolder patern扩展BaseAdapter。

10 个答案:

答案 0 :(得分:26)

我遇到了同样的问题,我找到了解决方案:

<强>步骤:

1)首先从this链接下载CustomViewPager班级。

2)使用下面提到的那个类:

在Java中:

CustomViewPager mViewPager;
mViewPager = (CustomViewPager) findViewById(R.id.swipePager);
mViewPager.setOffscreenPageLimit(0);

在XML中:

<com.yourpackagename.CustomViewPager 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipePager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

现在一次只能加载一个页面。

P.S :根据问题的要求,我发布了Viewpager的解决方案。我还没有对TabLayout做过同样的尝试。如果我找到任何解决方案,我会更新答案。

答案 1 :(得分:16)

据我所知,使用ViewPager 时不可行。至少不是,当你希望你的页面可以刷卡时。

因此解释非常简单:

当您在两个页面之间滑动时,当两个页面都需要可见时会有一个点,因为当其中一个页面不存在时,您无法在两个页面之间滑动

有关详情,请参阅此问题: ViewPager.setOffscreenPageLimit(0) doesn't work as expected

CommonsWare在他answer的评论中提供了很好的解释。

答案 2 :(得分:11)

  

但我需要一次加载一页因为内存问题。

这假设你得到OutOfMemoryError s。

  

我是否必须使用旧式tabhost等?

是,或FragmentTabHost或操作栏标签。

  

或者有没有办法/黑客我可以让我的viewPager一次加载一页?

不,原因很简单,ViewPager一次需要多个页面来进行滑动动画。您可以使用ViewPager并轻扫来查看此内容。

或者,您可以修复感知到的记忆问题。假设此应用程序与that you reported on earlier today相同,则只使用7MB的堆空间。如果您的剩余堆高度分散,那只会导致OutOfMemoryError s。有一些内存管理策略(例如inBitmap BitmapOptions用于创建来自外部源的位图),有助于解决此类碎片问题。

  

我的适配器使用ViewHolder patern扩展BaseAdapter。

BaseAdapter适用于AdapterView,而不是ViewPager

答案 3 :(得分:3)

通过这种方法,您可以使用视图分页器一次在选项卡布局中加载一页`

  @Override
    public void onResume() {
        super.onResume();
        if (getUserVisibleHint() && !isVisible) {
            Log.e("~~onResume: ", "::onLatestResume");
           //your code
        }
        isVisible = true;
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

        if (isVisibleToUser && isVisible) {
            Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                   //your code
                }
            }, 500);

        }
    }

`

答案 4 :(得分:1)

覆盖setUserVisibleHint,并在每个片段中添加如下所示的postDelayed

override fun setUserVisibleHint(isVisibleToUser: Boolean) {
    if (isVisibleToUser)
        Handler().postDelayed({
            if (activity != null) {
                // Do you stuff here 
            }
        }, 200)
    super.setUserVisibleHint(isVisibleToUser)
}

我可以通过这种方式进行管理,并且现在对我来说可以正常工作。

答案 5 :(得分:1)

首先,复制SmartFragmentStatePagerAdapter.java,该文件可在ViewPager中智能缓存已注册的片段。它通过重写InstantiateItem()方法并在内部缓存所有创建的片段来实现。这解决了需要访问ViewPager中的当前项目的常见问题。

现在,我们想在声明适配器时从上面复制的SmartFragmentStatePagerAdapter进行扩展,以便我们可以利用状态分页器的更好的内存管理:

公共抽象类SmartFragmentStatePagerAdapter扩展FragmentStatePagerAdapter {     //稀疏数组以跟踪内存中已注册的片段     私有SparseArray registrationFragments = new SparseArray();

public SmartFragmentStatePagerAdapter(FragmentManager fragmentManager) {
    super(fragmentManager);
}

// Register the fragment when the item is instantiated
@Override
public Object instantiateItem(ViewGroup container, int position) {
    Fragment fragment = (Fragment) super.instantiateItem(container, position);
    registeredFragments.put(position, fragment);
    return fragment;
}

// Unregister when the item is inactive
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    registeredFragments.remove(position);
    super.destroyItem(container, position, object);
}

// Returns the fragment for the position (if instantiated)
public Fragment getRegisteredFragment(int position) {
    return registeredFragments.get(position);
}

}

//现在从SmartFragmentStatePagerAdapter扩展,以获取更多动态ViewPager项     公共静态类MyPagerAdapter扩展了SmartFragmentStatePagerAdapter {     私有静态整数NUM_ITEMS = 3;

    public MyPagerAdapter(FragmentManager fragmentManager) {
        super(fragmentManager);
    }

    // Returns total number of pages
    @Override
    public int getCount() {
        return NUM_ITEMS;
    }

    // Returns the fragment to display for that page
    @Override
    public Fragment getItem(int position) {
        switch (position) {
        case 0: // Fragment # 0 - This will show FirstFragment
            return FirstFragment.newInstance(0, "Page # 1");
        case 1: // Fragment # 0 - This will show FirstFragment different title
            return FirstFragment.newInstance(1, "Page # 2");
        case 2: // Fragment # 1 - This will show SecondFragment
            return SecondFragment.newInstance(2, "Page # 3");
        default:
            return null;
        }
    }

    // Returns the page title for the top indicator
    @Override
    public CharSequence getPageTitle(int position) {
        return "Page " + position;
    }

}

答案 6 :(得分:1)

对此我有一个答案。上面提到的setUserVisibleHint()方法已被弃用,您可以使用setMaxLifecycle()方法。要仅加载可见片段,您必须在viewpager适配器中将行为设置为 BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT 。即在构造函数中。为了处理片段,请在片段中使用onResume()方法。

这样,您一次只能在viewpager中加载一个片段。

答案 7 :(得分:0)

您可以使用FragmentStatePagerAdapter。这允许寻呼机保持更少的内存。一旦它们无法访问,它就会从FragmentManager中完全删除Fragment实例。已删除的Fragments的状态存储在FragmentStatePagerAdapter中。返回到现有项目并恢复状态后,将重新创建Fragment实例。

public static class MyAdapter extends FragmentStatePagerAdapter {
    public MyAdapter(FragmentManager fm) {
        super(fm);
    }

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

    @Override
    public Fragment getItem(int position) {
        return ArrayListFragment.newInstance(position);
    }
}

答案 8 :(得分:0)

您实际上不需要自定义ViewPager。

我遇到了同样的问题,我确实这样做了。

  • setOffscreenPageLimit()保留为1。
  • 使用片段的onResumeonPause生命周期方法。

初始化和释放这些生命周期方法中的内存。

答案 9 :(得分:-1)

我知道这是一个老帖子,但我偶然发现了这个问题,如果加载片段,我发现了一个很好的解决方案。简单地说,通过覆盖setUserVisibleHint()来检查用户是否看到了片段。之后加载数据。

    @Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
        getData(1, getBaseUrl(), getLink());
    }
}