2

背景

我有一个 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,早餐,这是我的第一页,也是充满虚拟数据的页面,确实被通知其数据集已更改。有趣的是,其他人不是。


问题..

那么,至于我最初的问题:我是否正确地实现了片段的单例分组?如果是这样,还有哪些其他因素可能导致我遇到的奇怪行为。提前致谢(=

4

0 回答 0