背景
我有一个 ViewPager,最多可以显示 4 个片段。在任何给定时间可用的数字都是动态的(可以是 1、2、3 或 4)。让这些片段自己管理是最有意义的。我的意思是他们是单身人士。我没有使用 new 关键字创建新片段,而是编写了一个“getInstance(String key)”方法,该方法尝试从映射中检索指定键的片段,或者如果它不存在于映射中,则创建一个新实例,将片段放置在具有给定键的映射中,使用包含该键的包设置片段参数,以便片段可以在 onCreate() 中检索它,然后返回该片段的新实例。
对于那些不关注的人,这是代码:
public class DishListFragment extends ListFragment {
public static final String MENU = "menu";
...
private static Map<String, DishListFragment> mInstances = new HashMap<String, DishListFragment>();
public static DishListFragment getInstance(String menuKey) {
if (mInstances.containsKey(menuKey))
return mInstances.get(menuKey);
Bundle b = new Bundle();
b.putString(MENU, menuKey);
DishListFragment dlf = new DishListFragment();
dlf.setArguments(b);
mInstances.put(menuKey, dlf);
return dlf;
}
}
您可能已经注意到这不是线程安全的。
演练
OnCreate,我的主要活动设置它的视图,然后生成一个 AsyncTask 负责从服务器获取数据,该服务器将填充我的 DishListFragments。同时,主要活动继续进行并设置 PagerAdapter。当 PagerAdapter 请求一个新的 DishListFragment 时,数字被动态转换为一个 key,值来自 DishListFragment.getInstance(key); 返回方法。最初,ListFragments 观察到的内容类具有虚拟数据,因此始终显示一页,因此始终有一页可供 ViewPager 显示。
当 AsyncTask 启动时,会显示一个进度对话框。完成后,它会关闭进度对话框并在我的活动中调用一个方法,然后在我的内容类中设置数据。然后调用一个方法 refresh(),它告诉所有存在的 DishListFragment 通知它们的适配器数据集已更改。该方法完成后,会通知 ViewPagerAdapter 其数据集已更改。
在我的主要活动中:
public void onRetrieveData(Result result) {
switch(result.getCode()) {
case Result.SUCCESS:
Log.i(UITHREAD, "Menu successfully loaded!");
/* On SUCCESS the MenuContent class should be given the data and
* the adapters notified. */
mRequestedDate = mPendingDate;
MenuContent.setMenuData(result.getValue());
DishListFragment.refresh();
mMenuPagerAdapter.notifyDataSetChanged();
...
}
}
以及 DishListFragment 类中的刷新方法:
public static void refresh() {
for (String key : mInstances.keySet()) {
mInstances.get(key).mListAdapter.notifyDataSetChanged();
Log.d("glic", "DishListFragment: " + key + " refreshed");
}
Log.d("glic", "DishListFragments refreshed");
}
问题
问题是,在冷启动时,除了第一页之外的所有内容都会更新。此外,从我的 Logcat 输出中,我收集到我的地图中只有一个 DishListFragment:
10-18 22:11:41.624: I/##############(16802): Menu successfully loaded!
10-18 22:11:41.744: D/glic(16802): DishListFragment: breakfast refreshed
10-18 22:11:41.744: D/glic(16802): DishListFragments refreshed
10-18 22:11:41.744: D/GLIC(16802): lunch
但是,我的视图寻呼机显示 4 个页面,其中第一个页面仍然包含虚拟数据。如果我旋转屏幕,第一页会更新并显示正确的信息。此外,如果我在虚拟列表中选择一个项目,则会显示一个详细信息片段,其中包含我选择的项目位置的真实(来自服务器)信息——即使我只选择了一个虚拟项目。
我的第一个想法是我可能有两个单例片段实例。一个包含一个包含初始虚拟数据片段的映射,另一个包含从服务器返回的真实数据。我想这是可能的,因为我的单例不是线程安全的。但是,我认为这不会引起任何问题。我的 DishListFragment 不包含它们显示的数据,它们只观察它,所以无论我可能有多少个相同的DishListFragment 实例(相同的页面),它们都应该观察相同的数据并且不应该显示不同的数据 - - 解析和添加来自服务器的新数据时清除虚拟数据。
但是,我的 mInstances 映射的两个实例可以解释为什么视图没有更新。也许只有一组 DishListFragments 中的适配器被通知其数据集已更改。不过,根据我的 Logcat,早餐,这是我的第一页,也是充满虚拟数据的页面,确实被通知其数据集已更改。有趣的是,其他人不是。
问题..
那么,至于我最初的问题:我是否正确地实现了片段的单例分组?如果是这样,还有哪些其他因素可能导致我遇到的奇怪行为。提前致谢(=