Viewpager Adapter getItem 总是调用索引 0 和 1

Viewpager Adapter getItem always called for index 0 and 1

我只是想知道 viewpager 及其适配器总是为索引 0 和 1 调用 getItem() 方法是否是正常行为,即使我立即设置当前位置也是如此。

这是我的代码:

mNewsPagerAdapter = new NewsDetailPagerAdapter(getChildFragmentManager());
mNewsPagerAdapter.updateNewsList(news);

mViewPager = (ViewPager) mView.findViewById(R.id.horizontal_view_pager);
mViewPager.setPageMargin(2);
mViewPager.setPageMarginDrawable(R.color.black);

mViewPager.setAdapter(mNewsPagerAdapter);
mViewPager.setCurrentItem(mCurrentPositionPager, false);

如果我使用此 viewpager 从概述 activity 切换到详细信息 activity,则适配器始终为位置 0 和 1 及之后调用 getItem() 方法getItem() 方法用于 mOriginalPosition 及其邻居的位置。我想知道这是否是正确的行为,或者我是否错过了以正确方式实施它的一些东西。感谢您的帮助:)

编辑:添加了我的适配器代码

public class NewsDetailPagerAdapter extends FragmentStatePagerAdapter {

private SparseArray<Fragment> mPageReferenceMap = new SparseArray<Fragment>();

private ArrayList<News> mNewsList;

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

/**
 * Setzt die neuen News.
 **/
public void updateNewsList(ArrayList<News> list) {
    mNewsList = list;
}

@Override
public Fragment getItem(int position) {
    Log.d("debug", "getItem position:" + position);
    News newsItem = mNewsList.get(position);


    NavigationFragment fragment = new NavigationFragment();

    mPageReferenceMap.put(position, fragment);

    return fragment;
}


@Override
public int getCount() {
    return mNewsList.size();
}

@Override
public int getItemPosition(Object object) {
    return POSITION_NONE;
}

public Fragment getFragment(int position) {
    return mPageReferenceMap.get(position);
}

}

实际上这是正常行为。事实上,当您将 ViewPager 与适配器相关联时,适配器会创建第一个可见布局(索引 0)结束下一个(索引 1)。这是在 "setAdapter" 中默认完成的。然后,当您设置不同的位置时,适配器将实例化所选索引处的片段,前一个和下一个。

这是通常的 ViewPager setAdapter 代码:

public void setAdapter(PagerAdapter adapter) {
    if (mAdapter != null) {
        mAdapter.setViewPagerObserver(null);
        mAdapter.startUpdate(this);
        for (int i = 0; i < mItems.size(); i++) {
            final ItemInfo ii = mItems.get(i);
            mAdapter.destroyItem(this, ii.position, ii.object);
        }
        mAdapter.finishUpdate(this);
        mItems.clear();
        removeNonDecorViews();
        mCurItem = 0;
        scrollTo(0, 0);
    }

    final PagerAdapter oldAdapter = mAdapter;
    mAdapter = adapter;
    mExpectedAdapterCount = 0;

    if (mAdapter != null) {
        if (mObserver == null) {
            mObserver = new PagerObserver();
        }
        mAdapter.setViewPagerObserver(mObserver);
        mPopulatePending = false;
        final boolean wasFirstLayout = mFirstLayout;
        mFirstLayout = true;
        mExpectedAdapterCount = mAdapter.getCount();
        if (mRestoredCurItem >= 0) {
            mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
            setCurrentItemInternal(mRestoredCurItem, false, true);
            mRestoredCurItem = -1;
            mRestoredAdapterState = null;
            mRestoredClassLoader = null;
        } else if (!wasFirstLayout) {
            populate();
        } else {
            requestLayout();
        }
    }

    if (mAdapterChangeListener != null && oldAdapter != adapter) {
        mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter);
    }
}

为了改变 ViewPager 的行为,您可以扩展经典的 ViewPager 覆盖 setAdapter 方法并将 mCurrItem 设置到所需的位置。

希望对您有所帮助

编辑:

经过不同的测试,我们找到了解决方案。

如果在 ViewPager 布局可见后设置 ViewPager 适配器,则加载项 0 和 1。 如果您想避免此行为,但无法在布局可见之前设置适配器(因为您正在等待数据),那么您可以使用此解决方法:

1) 最初将 ViewPager 可见性设置为 GONE

2) 收到所有数据后,更新适配器并设置当前项目值

3) 最后将 ViewPager 可见性设置为 VISIBLE

在这里你可以找到一个例子:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    View v = inflater.inflate(R.layout.detail_overview_fragment, container, false);

    final int position = getArguments().getInt("position");
    final ViewPager viewPager = (ViewPager) v.findViewById(R.id.viewpager);
    viewPager.setVisibility(View.GONE);

    Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            viewPager.setAdapter(new PagerAdapter(getChildFragmentManager()));
            viewPager.setCurrentItem(position);
            viewPager.setVisibility(View.VISIBLE);

        }
    },5000);

    return v;
}

是的,这是 ViewPager 的正常行为,因为它会始终尝试通过呈现受绘图区域限制的选项卡来领先于用户。我个人不建议创建自定义 ViewPager,因为除非您真的知道自己在做什么,否则您几乎肯定会破坏功能。您的适配器 class 应如下所示:

public class YourCustomPagerAdapter extends FragmentStatePagerAdapter {
    private List<Fragment> fragmentList = new ArrayList<>();
    private List<String> titleList = new ArrayList<>();

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

    public void addFragment(Fragment fragment, String title) {
        fragmentList.add(fragment);
        titleList.add(title);
    }

    @Override
    public Fragment getItem(int position) {
        return fragmentList.get(position);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        super.getPageTitle(position);
        return titleList.get(position);
    }

    @Override
    public int getCount() {
        return fragmentList.size();
    }
}

你应该这样添加你的片段:

 @Override
 public void onCreate(Bundle savedInstanceState) {
     ...
     YourCustomPagerAdapter adapter = new YourCustomPagerAdapter (getSupportFragmentManager());
     adapter.addFragment(FragmentOne.newInstance(), "Frag 1");
     adapter.addFragment(FragmentTwo.newInstance(), "Frag 2");
     viewPager.setAdapter(adapter);
     ...
 }

我认为错误是适配器:

   /**
     * Setzt die neuen News.
     **/
    public void updateNewsList(ArrayList<News> list) {
        //mNewsList = list;
        mNewsList.clear();
        mNewsList.addAll(list);
        /**
         * Notifies the attached observers that the underlying data has been changed
         * and any View reflecting the data set should refresh itself.
         */
        this.notifyDataSetChanged();
    }

错误原因:此列表是该适配器的不同实体。

这很正常(在我看来也很聪明)。 ViewPager class 有一个名为 mOffscreenPageLimit 的 属性,默认值为 1。此数字决定了 Viewpager 将预加载当前页面左侧和右侧的页面数。例如,您有 10 个页面,当前位置为 5,mOffcreenPageLimit 为 1,则将加载位置 4 和 6 的页面。

您可以通过调用此方法

来更改此 属性
viewpager. setOffscreenPageLimit(int)

如果传入小于1的整数,则无效。