我无法更新ViewPager中的内容 .
一个问题:FragmentPagerAdapter类中的方法instantiateItem()和getItem()的关系和正确用法是什么?
我只使用getItem()实例化并返回我的片段:
@Override
public Fragment getItem(int position) {
return new MyFragment(context, paramters);
}
这很好用(但据说我不能改变内容) .
所以我发现了这个:ViewPager PagerAdapter not updating the View
特别是在其中讨论了方法instantiateItem():
“我的方法是对instantiateItem()方法中的任何实例化视图使用setTag()方法”
所以现在我想实现instantiateItem()才能做到这一点 . 但我不知道我必须返回那里(return是Object)和getItem(int position)的关系是什么?
目前我正在使用getItem来实例化Fragment,这是错的吗?但是,我是否必须将片段放在实例变量中,或者根本不实现getItem()?我只是不明白 .
我试过阅读reference:
public abstract Fragment getItem(int position)返回与指定位置关联的Fragment . public Object instantiateItem(ViewGroup container,int position)创建给定位置的页面 . 适配器负责将视图添加到此处给出的容器,但它必须确保在从finishUpdate(ViewGroup)返回时完成此操作 . 参数container包含将在其中显示页面的View . position要实例化的页面位置 . 返回返回表示新页面的Object . 这不需要是View,但可以是页面的其他容器 .
......但我仍然不明白它们是如何相关的以及我必须做些什么 .
这是我的代码 . 我正在使用支持包v4 .
ViewPagerTest
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);
}
}
MyFragmentAdapter
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;
}
}
MyFragment
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
18 回答
如果您想使用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存在问题,可能会或可能不会对您的用例造成影响 .
此外,链接也没有什么解决方案..这可能适合您的要求 .
我遇到了同样的问题,我搜索了太多次 . stackoverflow或谷歌给出的任何答案都不是我的问题的解决方案 . 我的问题很简单 . 我有一个列表,我用viewpager显示这个列表 . 当我向列表的头部添加一个新元素时,我刷新了viewpager nothings的更改 . 我的最终解决方案非常容易,任何人都可以使用 . 当一个新元素添加到列表并想要刷新列表时 . 首先将viewpager适配器设置为null,然后重新创建适配器并将i设置为viewpager .
确保您的适配器必须扩展FragmentStatePagerAdapter
使用FragmentPagerAdapter或FragmentStatePagerAdapter时,最好只处理
getItem()
而不是触及instantiateItem()
. PagerAdapter上的instantiateItem()
-destroyItem()
-isViewFromObject()
接口是FragmentPagerAdapter用于实现更简单的getItem()
接口的低级接口 .在进入这个之前,我应该澄清一下
这个答案的早期版本错误地使用FragmentPagerAdapter作为它的例子 - 这将无法工作,因为FragmentPagerAdapter在第一次显示片段后永远不会销毁片段 .
我不建议您链接的帖子中提供的
setTag()
和findViewWithTag()
解决方法 . 正如您所发现的那样,使用setTag()
和findViewWithTag()
并不是一个很好的匹配 .正确的解决方案是覆盖
getItemPosition()
. 调用notifyDataSetChanged()
时,ViewPager会在其适配器中的所有项目上调用getItemPosition()
,以查看是否需要将它们移动到其他位置或删除 .默认情况下,
getItemPosition()
返回POSITION_UNCHANGED
,这意味着,"This object is fine where it is, don't destroy or remove it."返回POSITION_NONE
修复问题,而不是说,"This object is no longer an item I'm displaying, remove it."因此它具有删除和重新创建适配器中每个项目的效果 .这是一个完全合法的修复!此修复使notifyDataSetChanged的行为类似于常规适配器而没有视图回收 . 如果您实施此修复程序并且性能令人满意,那么您将参加比赛 . 任务完成 .
如果您需要更好的性能,可以使用更高级的
getItemPosition()
实现 . 以下是寻呼机从字符串列表中创建片段的示例:通过此实现,将仅显示显示新 Headers 的片段 . 显示仍在列表中的 Headers 的任何片段将被移动到列表中的新位置,并且将销毁具有不再在列表中的 Headers 的片段 .
如果片段尚未重新创建,但仍需要更新,该怎么办?生命片段的更新最好由片段本身处理 . 毕竟这是拥有片段的优势 - 它是它自己的控制器 . 片段可以将监听器或观察者添加到
onCreate()
中的另一个对象,然后在onDestroy()
中将其删除,从而自行管理更新 . 您不必像在适用于ListView或其他AdapterView类型的适配器中那样将所有更新代码放在_706609中 .最后一件事 - 只是因为FragmentPagerAdapter没有破坏片段并不意味着getItemPosition在FragmentPagerAdapter中完全没用 . 您仍然可以使用此回调来重新排序ViewPager中的片段 . 但它永远不会从FragmentManager中完全删除它们 .
而不是从
getItemPosition()
返回POSITION_NONE
并导致完整视图重新创建,请执行以下操作:你的片段应该实现
UpdateableFragment
接口:和界面:
你的数据类:
对于那些仍然面对的人当我有一个包含7个片段的ViewPager时,我遇到的同样的问题 . 这些片段的默认值是从api服务加载英语内容但这里的问题是我想从设置活动更改语言,在完成设置活动之后我希望主活动中的ViewPager刷新片段以匹配来自用户的语言选择如果用户在这里选择了阿拉伯语,我会在第一次工作时加载阿拉伯语内容
1- You must use FragmentStatePagerAdapter as mentioned above.
2-on mainActivity i覆盖onResume并执行以下操作
3-i覆盖了mPagerAdapter中的getItemPosition()并使其返回POSITION_NONE .
像魅力一样工作
我遇到了这个问题,今天终于解决了,所以我写下了我所学到的东西,希望对于那些刚接触Android的
ViewPager
并像我一样更新的人有所帮助 . 我在API级别17中使用FragmentStatePagerAdapter
,目前只有2个片段 . 我认为肯定有些事情不对,请纠正我,谢谢 .必须将序列化数据加载到内存中 . 这可以使用
CursorLoader
/AsyncTask
/Thread
来完成 . 它是否自动加载取决于您的代码 . 如果您使用的是CursorLoader
,则会自动加载,因为有一个已注册的数据观察者 .调用
viewpager.setAdapter(pageradapter)
后,将不断调用适配器的getCount()
来构建片段 . 因此,如果正在加载数据,getCount()
可以返回0,因此您不需要为没有显示的数据创建虚拟片段 .加载数据后,由于
getCount()
仍为0,适配器不会自动构建片段,因此我们可以设置getCount()
返回的实际加载的数据编号,然后调用适配器的notifyDataSetChanged()
.ViewPager
开始按内存中的数据创建片段(只是前2个片段) . 它在notifyDataSetChanged()
返回之前完成 . 然后ViewPager
拥有您需要的正确片段 .如果数据库和内存中的数据都已更新(直写),或者内存中的数据已更新(写回),或者只更新数据库中的数据 . 在最后两种情况下,如果数据没有自动从数据库加载到内存(如上所述) .
ViewPager
和寻呼机适配器只处理内存中的数据 .因此,当内存中的数据更新时,我们只需要调用适配器的
notifyDataSetChanged()
. 由于片段已经创建,因此在notifyDataSetChanged()
返回之前将调用适配器的onItemPosition()
. 在getItemPosition()
中无需做任何事情 . 然后更新数据 .在代码中的
notifyDataSetChanged()
之后,在ViewPager上尝试destroyDrawingCache()
.经过几个小时的挫折,同时尝试所有上述解决方案,以解决这个问题,并尝试许多其他类似问题的解决方案,如this,this和this这些都与我失败解决这个问题,并使
ViewPager
摧毁旧的Fragment
并填写pager
与新的Fragment
. 我已经解决了以下问题:1) 使
ViewPager
类扩展FragmentPagerAdapter
,如下所示:2) 为
ViewPager
创建一个项目,用于存储title
和fragment
,如下所示:3) 使
ViewPager
的构造函数将我的FragmentManager
实例存储在我的class
中,如下所示:4) 创建一个方法,通过直接删除
fragmentManager
本身中的所有先前fragment
来重新设置adapter
数据与新数据,以使adapter
再次从新列表中设置新fragment
,如下所示:5) 从容器
Activity
或Fragment
不要使用新数据重新初始化适配器 . 通过方法setPagerItems
使用新数据设置新数据,如下所示:我希望它有所帮助 .
由于某些原因,没有一个答案对我有用,所以我必须覆盖restoreState方法而不在我的fragmentStatePagerAdapter中调用super . 码:
我稍微修改了Bill Phillips提供的解决方案以满足我的需求
这样
getItemPosition()
只返回当调用getItemPosition
时当前在FragmentManager
中的那些片段的POSITION_NONE
. (请注意,此FragmentStatePager
和与之关联的ViewPager
包含在不在活动中的片段中)我有类似的问题,但不想信任现有的解决方案(硬编码标签名称等),我不能让M-WaJeEh的解决方案适合我 . 这是我的解决方案:
我保留了对数组中getItem中创建的片段的引用 . 只要活动没有因为configurationChange或缺少内存或其他原因而被破坏( - >当返回活动时,片段返回到它们的最后状态而没有再次调用'getItem',因此没有更新数组) .
为了避免这个问题,我实现了instantiateItem(ViewGroup,int)并在那里更新我的数组,如下所示:
所以,一方面我很高兴我找到了一个有效的解决方案对我而言,我想与你分享,但我也想问一下其他人是否尝试过类似的东西,是否有任何理由不这样做呢?到目前为止它对我来说非常好......
我使用EventBus库来更新
ViewPager
中的Fragment
内容 . 逻辑很简单,就像document of EventBus how to do一样 . 它不需要控制FragmentPagerAdapter
实例 . 代码在这里:1:定义事件
定义更新所需的消息 .
2.Prepare订阅者
在片段中写下需要更新的代码 .
3.Post事件
在下面的代码中写下需要更新参数的其他
Activity
或其他Fragment
我一直在尝试这么多不同的方法,没有一个能真正解决我的问题 . 以下是我通过大家提供的各种解决方案解决问题的方法 . 感谢大家 .
我只想在onResume()之后刷新第0页 .
在我的FragmentsMain中,有一个公共整数“页面”,可以告诉我它是否是我要刷新的页面 .
我知道党迟到了 . 我在
FragmentPagerAdapter#notifyDataSetChanged();
之后调用TabLayout#setupWithViewPager(myViewPager);
修复了问题这个解决方案对每个人都不起作用,但就我而言,我的ViewPager中的每个Fragment都是一个不同的类,一次只存在其中一个 .
有了这个限制,这个解决方案是安全的,应该可以安全地用于 生产环境 .
如果您有相同片段的多个版本,则可以使用相同的策略调用这些片段上的方法,以确定它是否是您要更新的片段 .
这可能对某人有所帮助 - 在我的情况下,当插入新页面时,视图寻呼机要求两次现有片段的位置,但不要求新项目的位置,导致不正确的行为和数据不显示 .
复制FragmentStatePagerAdapter的源代码(好像很久没有更新) .
覆盖notifyDataSetChanged()
我已经完成了上面的所有答案和其他一些帖子,但仍然找不到适合我的东西(使用不同的片段类型以及动态添加和删除标签) . FWIW以下方法对我有用(如果其他人有同样的问题) .
如果要在索引的基础上重新创建或重新加载片段,请使用FragmentStatePagerAdapter而不是FragmentPagerAdapter例如,如果要重新加载FirstFragment以外的片段,可以检查实例并返回这样的位置