バックグラウンド
最大 4 つのフラグメントを表示する ViewPager があります。いつでも使用できる数は動的です (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 では、メイン アクティビティがビューを設定し、DishListFragments にデータを入力するサーバーからデータを取得する AsyncTask を生成します。その間、メイン アクティビティは続行され、PagerAdapter が設定されます。PagerAdapter が新しい DishListFragment を要求すると、数値は動的にキーに変換され、値は DishListFragment.getInstance(key); から取得されます。メソッドが返されます。最初は、ListFragments によって観察されるコンテンツ クラスにはダミー データがあるため、常に 1 つのページが表示され、ViewPager が表示できるページが常に 1 つ存在します。
AsyncTask が開始されると、進行状況ダイアログが表示されます。完了すると、進行状況ダイアログが閉じられ、アクティビティのメソッドが呼び出され、コンテンツ クラスにデータが設定されます。次に、メソッド refresh() が呼び出され、存在するすべての DishListFragments に、データセットが変更されたことをアダプターに通知するように指示します。そのメソッドが完了すると、データセットが変更されたことが 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 クラスの refresh メソッド:
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 が 1 つしかないことがわかります。
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 ページが表示され、最初のページにはまだダミー データが含まれています。画面を回転すると、最初のページが更新され、正しい情報が表示されます。また、ダミー リストでアイテムを選択すると、選択したアイテムの位置に関する実際の (サーバーからの) 情報を含む詳細フラグメントが表示されます (ダミー アイテムのみを選択した場合でも)。
私が最初に考えたのは、シングルトン フラグメントのインスタンスが 2 つある可能性があるということです。1 つは最初のダミー データを含むフラグメントを含むマップで、もう 1 つはサーバーから返された実際のデータを含むマップです。私のシングルトンはスレッドセーフではないので、これは可能だと思います。ただし、これで問題が発生することはないと思います。私の DishListFragments には、表示するデータが含まれていません。それらはそれを観察するだけなので、同じDishListFragment (同じページに対して同じ) のインスタンスがいくつあるかに関係なく、それらはすべて同じデータを観察し、異なるデータを表示するべきではありません - - サーバーからの新しいデータが解析されて追加されると、ダミー データはクリアされます。
しかし、私の mInstances マップの 2 つのインスタンスは、ビューが更新されない理由を説明している可能性があります。おそらく、DishListFragments のセットの 1 つのみのアダプターに、データセットが変更されたことが通知されています。ただし、私の Logcat によると、私の最初のページであり、ダミー データで満たされているbreakfastには、データセットが変更されたことが実際に通知されています。興味深いことに、他の人はそうではありません。
質問..
それで、私の元の質問については、フラグメントのシングルトングループ化を正しく実装していますか? もしそうなら、私が経験している奇妙な行動を引き起こしている可能性のある他の要因. よろしくお願いします(=