按照通常使用ListView的习惯做法,如果你只是更新保存Fragment的List数据,然后调用adapter的notifyDataSetChanged()是不会起作用的.
搜索了下发现此问题普遍存在,多数是说先移除Fragment再notifyDataSetChanged(),因为FragmentPagerAdapter内部会缓存Fragment,但是经测试发现仅仅这样干是不行的。
这可能是Android一个BUG, 与此问题相关的主要有两个方法:
- getItemPosition()
- instantiateItem()
具体的分析内容参见原文,那么重写后的adapter如下:
1 /**
2 * 加载显示Fragment的ViewPagerAdapter基类
3 * 提供可以刷新的方法
4 *
5 * @author Fly
6 * @e-mail 1285760616@qq.com
7 * @time 2018/3/22
8 */
9 public class BaseFragmentPagerAdapter extends FragmentPagerAdapter {
10 private List<BaseFragment> mFragmentList;
11 private FragmentManager mFragmentManager;
12 /**下面两个值用来保存Fragment的位置信息,用以判断该位置是否需要更新*/
13 private SparseArray<String> mFragmentPositionMap;
14 private SparseArray<String> mFragmentPositionMapAfterUpdate;
15
16 public BaseFragmentPagerAdapter(FragmentManager fm, List<BaseFragment> fragments) {
17 super(fm);
18 mFragmentList = fragments;
19 mFragmentManager = fm;
20 mFragmentList = fragments;
21 mFragmentPositionMap = new SparseArray<>();
22 mFragmentPositionMapAfterUpdate = new SparseArray<>();
23 setFragmentPositionMap();
24 setFragmentPositionMapForUpdate();
25 }
26
27 /**
28 * 保存更新之前的位置信息,用<hashCode, position>的键值对结构来保存
29 */
30 private void setFragmentPositionMap() {
31 mFragmentPositionMap.clear();
32 for (int i = 0; i < mFragmentList.size(); i++) {
33 mFragmentPositionMap.put(Long.valueOf(getItemId(i)).intValue(), String.valueOf(i));
34 }
35 }
36
37 /**
38 * 保存更新之后的位置信息,用<hashCode, position>的键值对结构来保存
39 */
40 private void setFragmentPositionMapForUpdate() {
41 mFragmentPositionMapAfterUpdate.clear();
42 for (int i = 0; i < mFragmentList.size(); i++) {
43 mFragmentPositionMapAfterUpdate.put(Long.valueOf(getItemId(i)).intValue(), String.valueOf(i));
44 }
45 }
46
47 /**
48 * 在此方法中找到需要更新的位置返回POSITION_NONE,否则返回POSITION_UNCHANGED即可
49 */
50 @Override
51 public int getItemPosition(Object object) {
52 int hashCode = object.hashCode();
53 //查找object在更新后的列表中的位置
54 String position = mFragmentPositionMapAfterUpdate.get(hashCode);
55 //更新后的列表中不存在该object的位置了
56 if (position == null) {
57 return POSITION_NONE;
58 } else {
59 //如果更新后的列表中存在该object的位置, 查找该object之前的位置并判断位置是否发生了变化
60 int size = mFragmentPositionMap.size();
61 for (int i = 0; i < size ; i++) {
62 int key = mFragmentPositionMap.keyAt(i);
63 if (key == hashCode) {
64 String index = mFragmentPositionMap.get(key);
65 if (position.equals(index)) {
66 //位置没变依然返回POSITION_UNCHANGED
67 return POSITION_UNCHANGED;
68 } else {
69 //位置变了
70 return POSITION_NONE;
71 }
72 }
73 }
74 }
75 return POSITION_UNCHANGED;
76 }
77
78 /**
79 * 将指定的Fragment替换/更新为新的Fragment
80 * @param oldFragment 旧Fragment
81 * @param newFragment 新Fragment
82 */
83 public void replaceFragment(BaseFragment oldFragment, BaseFragment newFragment) {
84 int position = mFragmentList.indexOf(oldFragment);
85 if (position == -1) {
86 return;
87 }
88 //从Transaction移除旧的Fragment
89 removeFragmentInternal(oldFragment);
90 //替换List中对应的Fragment
91 mFragmentList.set(position, newFragment);
92 //刷新Adapter
93 notifyItemChanged();
94 }
95
96 /**
97 * 将指定位置的Fragment替换/更新为新的Fragment,同{@link #replaceFragment(BaseFragment oldFragment, BaseFragment newFragment)}
98 * @param position 旧Fragment的位置
99 * @param newFragment 新Fragment
100 */
101 public void replaceFragment(int position, BaseFragment newFragment) {
102 BaseFragment oldFragment = mFragmentList.get(position);
103 removeFragmentInternal(oldFragment);
104 mFragmentList.set(position, newFragment);
105 notifyItemChanged();
106 }
107
108 /**
109 * 移除指定的Fragment
110 * @param fragment 目标Fragment
111 */
112 public void removeFragment(BaseFragment fragment) {
113 //先从List中移除
114 mFragmentList.remove(fragment);
115 //然后从Transaction移除
116 removeFragmentInternal(fragment);
117 //最后刷新Adapter
118 notifyItemChanged();
119 }
120
121 /**
122 * 移除指定位置的Fragment,同 {@link #removeFragment(BaseFragment fragment)}
123 * @param position
124 */
125 public void removeFragment(int position) {
126 BaseFragment fragment = mFragmentList.get(position);
127 //然后从List中移除
128 mFragmentList.remove(fragment);
129 //先从Transaction移除
130 removeFragmentInternal(fragment);
131 //最后刷新Adapter
132 notifyItemChanged();
133 }
134
135 /**
136 * 添加Fragment
137 * @param fragment 目标Fragment
138 */
139 public void addFragment(BaseFragment fragment) {
140 mFragmentList.add(fragment);
141 notifyItemChanged();
142 }
143
144 /**
145 * 在指定位置插入一个Fragment
146 * @param position 插入位置
147 * @param fragment 目标Fragment
148 */
149 public void insertFragment(int position, BaseFragment fragment) {
150 mFragmentList.add(position, fragment);
151 notifyItemChanged();
152 }
153
154 private void notifyItemChanged() {
155 //刷新之前重新收集位置信息
156 setFragmentPositionMapForUpdate();
157 notifyDataSetChanged();
158 setFragmentPositionMap();
159 }
160
161 /**
162 * 从Transaction移除Fragment
163 * @param fragment 目标Fragment
164 */
165 private void removeFragmentInternal(BaseFragment fragment) {
166 FragmentTransaction transaction = mFragmentManager.beginTransaction();
167 transaction.remove(fragment);
168 transaction.commitNow();
169 }
170
171 /**
172 * 此方法不用position做返回值即可破解fragment tag异常的错误
173 */
174 @Override
175 public long getItemId(int position) {
176 // 获取当前数据的hashCode,其实这里不用hashCode用自定义的可以关联当前Item对象的唯一值也可以,只要不是直接返回position
177 return mFragmentList.get(position).hashCode();
178 }
179
180 @Override
181 public Fragment getItem(int position) {
182 return mFragmentList.get(position);
183 }
184
185 @Override
186 public int getCount() {
187 return mFragmentList.size();
188 }
189
190 public List<BaseFragment> getFragments() {
191 return mFragmentList;
192 }
193 }
测试代码:
1 public class TestActivity extends FragmentActivity implements View.OnClickListener {
2 List<Fragment> mFragmentList;
3 ViewPager mViewPager;
4 public BaseFragmentPagerAdapter mAdapter;
5
6 @Override
7 protected void onCreate(Bundle savedInstanceState) {
8 super.onCreate(savedInstanceState);
9 setContentView(R.layout.activity_test);
10 mViewPager = findViewById(R.id.vp);
11 findViewById(R.id.btn_change).setOnClickListener(this);
12
13 mFragmentList = new ArrayList<>();
14 mFragmentList.add(getFg("AAA"));
15 mFragmentList.add(getFg("BBB"));
16 mFragmentList.add(getFg("CCC"));
17 mFragmentList.add(getFg("DDD"));
18 mAdapter = new BaseFragmentPagerAdapter(getSupportFragmentManager(), mFragmentList);
19 mViewPager.setAdapter(mAdapter);
20 }
21
22 private TestFragment getFg(String a){
23 TestFragment fragment = new TestFragment();
24 fragment.setTest(a);
25 return fragment;
26 }
27
28 @Override
29 public void onClick(View view) {
30 TestFragment eee = getFg("EEE");
31
32 //新增
33 mAdapter.addFragment(eee);
34 //插入
35 mAdapter.insertFragment(1, eee);
36
37 //删除
38 mAdapter.removeFragment(1);
39 //删除
40 mAdapter.removeFragment(mFragmentList.get(1));
41
42 //替换
43 mAdapter.replaceFragment(1, eee);
44 //替换
45 mAdapter.replaceFragment(mFragmentList.get(0), eee);
46 }
47 }
内容取自
https://blog.csdn.net/lyabc123456/article/details/79797552 |