我无法更新ViewPager中的内容。

FragmentPagerAdapter类中instantiateItem()和getItem()方法的正确用法是什么?

我只使用getItem()来实例化并返回我的片段:

@Override
public Fragment getItem(int position) {
    return new MyFragment(context, paramters);
}

这很有效。但我不能改变内容。

所以我发现这个:ViewPager PagerAdapter没有更新视图

我的方法是对instantiateItem()方法中的任何实例化视图使用setTag()方法

现在我想实现instantiateItem()来实现这一点。但我不知道我必须返回什么(类型是对象)和什么与getItem(int位置)的关系?

我读了参考资料:

public abstract Fragment getItem (int position) Return the Fragment associated with a specified position. public Object instantiateItem (ViewGroup container, int position) Create the page for the given position. The adapter is responsible for adding the view to the container given here, although it only must ensure this is done by the time it returns from finishUpdate(ViewGroup). Parameters container The containing View in which the page will be shown. position The page position to be instantiated. Returns Returns an Object representing the new page. This does not need to be a View, but can be some other container of the page.

但我还是不明白

这是我的代码。我用的是v4支持包。

查看页面测试

public class ViewPagerTest extends FragmentActivity {
    private ViewPager pager;
    private MyFragmentAdapter adapter; 

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.pager1);

        pager = (ViewPager)findViewById(R.id.slider);

        String[] data = {"page1", "page2", "page3", "page4", "page5", "page6"};

        adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
        pager.setAdapter(adapter);

        ((Button)findViewById(R.id.button)).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                reload();
            }
        });
    }

    private void reload() {
        String[] data = {"changed1", "changed2", "changed3", "changed4", "changed5", "changed6"};
        //adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
        adapter.setData(data);
        adapter.notifyDataSetChanged();
        pager.invalidate();

        //pager.setCurrentItem(0);
    }
}

我的片段适配器

class MyFragmentAdapter extends FragmentPagerAdapter {
    private int slideCount;
    private Context context;
    private String[] data;

    public MyFragmentAdapter(FragmentManager fm, int slideCount, Context context, String[] data) {
        super(fm);
        this.slideCount = slideCount;
        this.context = context;
        this.data = data;
    }

    @Override
    public Fragment getItem(int position) {
        return new MyFragment(data[position], context);
    }

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

    public void setData(String[] data) {
        this.data = data;
    }

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

我的片段

public final class MyFragment extends Fragment {
    private String text;

    public MyFragment(String text, Context context) {
        this.text = text;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.slide, null);
        ((TextView)view.findViewById(R.id.text)).setText(text);

        return view;
    }
}

这里还有一个人也有类似的问题,没有答案 http://www.mail-archive.com/android-developers@googlegroups.com/msg200477.html


当前回答

我已经浏览了上面所有的答案和其他一些帖子,但仍然找不到适合我的东西(不同的片段类型以及动态添加和删除选项卡)。FWIW遵循的方法对我来说是有效的(以防其他人有同样的问题)。

public class MyFragmentStatePageAdapter extends FragmentStatePagerAdapter {
    private static final String TAB1_TITLE = "Tab 1";
    private static final String TAB2_TITLE = "Tab 2";
    private static final String TAB3_TITLE = "Tab 3";

    private ArrayList<String> titles = new ArrayList<>();
    private Map<Fragment, Integer> fragmentPositions = new HashMap<>();


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


    public void update(boolean showTab1, boolean showTab2, boolean showTab3) {
        titles.clear();

        if (showTab1) {
            titles.add(TAB1_TITLE);
        }
        if (showTab2) {
            titles.add(TAB2_TITLE);
        }
        if (showTab3) {
            titles.add(TAB3_TITLE);
        }
        notifyDataSetChanged();
    }


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

    @Override
    public Fragment getItem(int position) {
        Fragment fragment = null;

        String tabName = titles.get(position);
        if (tabName.equals(TAB1_TITLE)) { 
            fragment =  Tab1Fragment.newInstance();
        } else if (tabName.equals(TAB2_TITLE)) {
            fragment =  Tab2Fragment.newInstance();
        } else if (tabName.equals(TAB3_TITLE)) {
            fragment =  Tab3Fragmen.newInstance();
        } 

        ((BaseFragment)fragment).setTitle(tabName);
        fragmentPositions.put(fragment, position);
        return fragment;
    }

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

    @Override
    public int getItemPosition(Object item) {
        BaseFragment fragment = (BaseFragment)item;
        String title = fragment.getTitle();
        int position = titles.indexOf(title);

        Integer fragmentPosition = fragmentPositions.get(item);
        if (fragmentPosition != null && position == fragmentPosition) {
            return POSITION_UNCHANGED;
        } else {
            return POSITION_NONE;
        }
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        super.destroyItem(container, position, object);
        fragmentPositions.remove(object);
    }
}

其他回答

如果您想使用FragmentStatePagerAdapter,请查看https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars&groupby=&sort=&id=37990。 FragmentStatePagerAdapter存在一些问题,可能会也可能不会给您的用例带来麻烦。

此外,link也有一些解决方案,少数可能适合您的要求。

当使用FragmentPagerAdapter或FragmentStatePagerAdapter时,最好只处理getItem()而根本不触及instantiateItem()。PagerAdapter上的instantiateItem()-destroyItem()-isViewFromObject()接口是一个低级接口,FragmentPagerAdapter使用它来实现更简单的getItem()接口。

在讨论这个问题之前,我应该澄清这一点

如果您想切换出正在显示的实际片段,您需要避免FragmentPagerAdapter并使用 FragmentStatePagerAdapter。

这个答案的早期版本错误地使用了FragmentPagerAdapter作为示例——这是行不通的,因为FragmentPagerAdapter在第一次显示后永远不会破坏一个片段。

我不推荐你链接的帖子中提供的setTag()和findViewWithTag()解决方案。正如您所发现的,使用setTag()和findViewWithTag()不能与片段一起工作,因此这不是一个很好的匹配。

正确的解决方案是重写getItemPosition()。当调用notifyDataSetChanged()时,ViewPager对其适配器中的所有项调用getItemPosition(),以查看是否需要将它们移动到不同的位置或删除。

默认情况下,getItemPosition()返回POSITION_UNCHANGED,这意味着“该对象在其所在位置很好,不要销毁或删除它。”返回POSITION_NONE可以解决这个问题,而是说:“这个对象不再是我正在显示的项目,删除它。”因此,它可以删除和重新创建适配器中的每个项。

这是一个完全合法的修复!此修复使notifyDataSetChanged的行为像常规适配器一样,没有视图回收。如果您实现了这个修复并且性能令人满意,那么您就可以开始比赛了。工作。

如果需要更好的性能,可以使用更花哨的getItemPosition()实现。下面是一个寻呼机从字符串列表中创建片段的例子:

ViewPager pager = /* get my ViewPager */;
// assume this actually has stuff in it
final ArrayList<String> titles = new ArrayList<String>();

FragmentManager fm = getSupportFragmentManager();
pager.setAdapter(new FragmentStatePagerAdapter(fm) {
    public int getCount() {
        return titles.size();
    }

    public Fragment getItem(int position) {
        MyFragment fragment = new MyFragment();
        fragment.setTitle(titles.get(position));
        return fragment;
    }

    public int getItemPosition(Object item) {
        MyFragment fragment = (MyFragment)item;
        String title = fragment.getTitle();
        int position = titles.indexOf(title);

        if (position >= 0) {
            return position;
        } else {
            return POSITION_NONE;
        }
    }
});

使用这个实现,只显示显示新标题的片段。任何显示标题仍在列表中的片段将被移动到列表中的新位置,而标题已不在列表中的片段将被销毁。

What if the fragment has not been recreated, but needs to be updated anyway? Updates to a living fragment are best handled by the fragment itself. That's the advantage of having a fragment, after all - it is its own controller. A fragment can add a listener or an observer to another object in onCreate(), and then remove it in onDestroy(), thus managing the updates itself. You don't have to put all the update code inside getItem() like you do in an adapter for a ListView or other AdapterView types.

最后一件事-仅仅因为FragmentPagerAdapter不破坏片段并不意味着getItemPosition在FragmentPagerAdapter中完全无用。你仍然可以使用这个回调在ViewPager中重新排序你的片段。但是,它永远不会将它们完全从FragmentManager中移除。

I have lived same problem and I have searched too much times. Any answer given in stackoverflow or via google was not solution for my problem. My problem was easy. I have a list, I show this list with viewpager. When I add a new element to head of the list and I refresh the viewpager nothings changed. My final solution was very easy anybody can use. When a new element added to list and want to refresh the list. Firstly set viewpager adapter to null then recreate the adapter and set i to it to viewpager.

myVPager.setAdapter(null);
myFragmentAdapter = new MyFragmentAdapter(getSupportFragmentManager(),newList);
myVPager.setAdapter(myFragmentAdapter);

确保您的适配器必须扩展FragmentStatePagerAdapter

对于那些仍然面临同样的问题,我以前遇到的时候,我有一个ViewPager与7个片段。这些片段默认从API服务加载英语内容,但这里的问题是,我想从设置活动和完成后更改语言 设置活动我想ViewPager在主活动刷新片段,以匹配从用户的语言选择和加载阿拉伯语内容,如果用户选择阿拉伯语在这里,我所做的工作从第一次

1-你必须使用FragmentStatePagerAdapter如上所述。

2-在mainActivity我覆盖onResume,并做以下

if (!(mPagerAdapter == null)) {
    mPagerAdapter.notifyDataSetChanged();
}

3-i覆盖了mPagerAdapter中的getItemPosition(),并使其返回POSITION_NONE。

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

工作很有魅力

由于某种原因,没有一个答案对我有用,所以我不得不重写restoreState方法,而不调用我的fragmentStatePagerAdapter中的super。代码:

private class MyAdapter extends FragmentStatePagerAdapter {

    // [Rest of implementation]

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {}

}