0

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 つしか使用できませんOnPageChangeListenerViewPageIndicatorにリスナーを割り当てたいライブラリも使用しているため、これは問題ですViewPager

このパターン (スワイプして表示されたフラグメント内のデータのアクティビティを通知する) は一般的である可能性があると想定しているため、このパターンに対する適切な解決策があるかどうか、および私が見つけた 3 つの具体的な問題について疑問に思っています。上で特定しました。

4

2 に答える 2

0

...このパターンと、上記で特定した 3 つの特定の問題に対する適切な解決策があるかどうか疑問に思っています。

それをパターンと呼ぶかどうかはわかりませんが、これOnPageChangeListenerが道です。

OnPageChangeListener は、フラグメントがそのデータをロードする前に呼び出すことができます (つまり、アイテムが非同期的にロードされる前に、フラグメントがビューにスワイプされます)。したがって、fragment.getLoadedItem() への呼び出しは null を返す場合があります。

まず、コードは最初から「利用可能なデータがない状況」を処理する必要があります。あなたはデータをロードし、彼らが取り組んでいるフラグメントが目に見えるものである場合にのみAsyncTasksタイトルを更新する仕事をします(のメソッドに対してテストされた位置フィールド)。ユーザーがページを切り替えてデータが利用可能になると、データがロードされたにタイトルの更新が処理されます (利用可能なデータがない場合は null が返されます)。特定の位置の を取得するには、以下のコードを使用できます。ItemFragmentViewPagergetCurrentItem()OnPageChangeListenerItemFragment

    ItemFragment itf = getSupportFragmentManager()
            .findFragmentByTag(
                    "android:switcher:" + R.id.theIdOfTheViewPager + ":"
                            + position);
    if (itf != null) {
        Item item = fragment.getLoadedItem();
            notifyItemLoaded(item);
    }

OnPageChangeListener は最初のページでは呼び出されないため (スワイプ操作の後など、ページが変更された場合のみ)、最初のページのアクティビティ タイトルは正しくありません。

上記を参照。

ViewPager クラスは、1 つの OnPageChangeListener のみを許可します。ViewPagerにリスナーを割り当てたいViewPageIndicatorライブラリも使用しているため、これは問題です

私は図書館についてあまり知識がないことを認めViewPagerIndicatorますが、そのサイトをざっと見たところ、次のことがわかりました。

(オプション) ビューページャーで OnPageChangeListener を使用する場合は、ページャーに直接設定するのではなく、インジケーターに設定する必要があります。

titleIndicator.setOnPageChangeListener(mPageChangeListener);

どこが限界なのかわからない。

于 2012-12-14T15:06:51.267 に答える
0

私の目的では、 Fragment が表示されているときにアクションを実行するためViewPager.OnPageChangeListener.onPageSelected()に と組み合わせて使用​​するとうまくいきました。も役立ちます。Fragment.onActivityCreated()Fragment.getUserVisibleHint()

于 2013-07-07T22:51:24.063 に答える