Android アプリに機能を実装する際に問題が発生しています。
セットアップは次のとおりです。
ItemPagerActivity
: ページャーを表示するフラグメントを含むアクティビティ。ItemPagerFragment
: 他のフラグメントをロードするページャーを含むフラグメント。カーソルを使用してフラグメントをロードします。ItemFragment
: データをロードするために非同期タスクを実行する、ページャー内のフラグメント。
私が欲しいのは次のとおりです。
- ページをスワイプすると、現在表示されているデータが に送信されます
ItemFragment
(ItemPagerActivity
具体的には、アイテムの名前がアクティビティのタイトルとして使用されます)。
ItemFragment
データがロードされたときに通知するリスナーを定義しました。
public class ItemFragment ... {
public interface OnItemLoadedListener {
public void onItemLoaded(Item item);
}
private Collection<OnItemLoadListener> listeners;
private class LoadItemTask extends AsyncTask<...> {
...
public void onPostExecute(Item item) {
notifyItemLoaded(item);
...
}
}
}
このフラグメントが でラップされActivity
ている場合、次の操作を行うだけでアクティビティのタイトルを設定できます。
public class ItemActivity {
public void onCreate(...) {
...
ItemFragment fragment = new ItemFragment();
fragment.registerItemLoadedListener(new ItemLoadedListener() {
public void onItemLoaded(Item item) {
setTitle("Item: " + item.getName());
}
});
...
}
}
これは簡単で、期待どおりに動作します。アクティビティが開始されると、フラグメントが作成され、アイテムが読み込まれ、アクティビティに通知され、タイトルが正しく更新されます。
しかし、ItemPagerFragment
では、フラグメントはプリエンプティブに読み込まれます。フラグメント 3 にスワイプすると、フラグメント 4 とフラグメント 5 が作成される可能性があります。ItemFragment
表示されたフラグメントが最後のロードを実行したフラグメントと一致しない可能性があるため、アイテムがロードされたときにクラスから通知を受け取ることはここでは正しくありません。
これで、ViewPager
クラスにはOnPageChangeListener
解決策になる可能性のある があります。スワイプすると、このリスナーが現在のページ番号で呼び出されます。そのページ番号から、アダプターからそのページを表すフラグメントを (何らかの方法で) 取得し、フラグメントからItem
データを取得し、リスナーにItem
がロードされたことを通知する必要があります。
public class ItemPagerFragment ... {
private Collection<OnItemLoadedListener> listeners;
public View onCreateView(...) {
...
ViewPager pager = (ViewPager) view.findViewById(R.id.pager):
pager.setOnPageChangeListener(new OnPageChangeListener() {
public void onPageChange(int pageNumber) {
ItemFragment fragment = getItemFragment(pageNumber);
Item item = fragment.getLoadedItem();
notifyItemLoaded(item);
}
});
...
}
}
クラスは、次のようItemPagerActivity
にクラスのリスナーとして登録さItemPagerFragment
れます。
class ItemPagerActivity ... {
public void onCreate(...) {
...
ItemPagerFragment fragment = new ItemPagerFragment();
fragment.registerOnItemLoadedListener(new OnItemLoadedListener() {
public void onItemLoaded(Item item) {
setTitle("Item: " + item.getName());
}
});
...
}
}
これは良さそうに見えますが、いくつかの問題があります。
は
OnPageChangeListener
、フラグメントがそのデータをロードする前に呼び出すことができます (つまり、アイテムが非同期的にロードされる前に、フラグメントがビューにスワイプされます)。したがって、への呼び出しは をfragment.getLoadedItem()
返す可能性がありnull
ます。は
OnPageChangeListener
最初のページでは呼び出されないため (スワイプ操作の後など、ページが変更された場合のみ)、最初のページのアクティビティ タイトルは正しくありません。この
ViewPager
クラスでは 1 つしか使用できませんOnPageChangeListener
。ViewPageIndicator
にリスナーを割り当てたいライブラリも使用しているため、これは問題ですViewPager
。
このパターン (スワイプして表示されたフラグメント内のデータのアクティビティを通知する) は一般的である可能性があると想定しているため、このパターンに対する適切な解決策があるかどうか、および私が見つけた 3 つの具体的な問題について疑問に思っています。上で特定しました。