web-dev-qa-db-ja.com

アクティビティとフラグメントの相互作用

複数のActivityを持つFragmentがあります。 DialogFragmentを表示するか、Fragmentsの1つから別のFragmentを開きたい。 ActivityFragmentsを開くタスクである必要があることを知っているので、代わりにいくつかのことを試しました。

[〜#〜]最初の[〜#〜]
getActivity()を使用してキャストしようとしたので、Activityのメソッドを呼び出してFragmentを表示できますが、これによりFragmentActivityの依存関係が作成されるため、追加を避けたいと思います。可能であれば依存関係。

[〜#〜]秒[〜#〜]
次に、リスナーがActivityFragmentを表示する必要があることを通知しようとしました。そこで、リスナーインターフェイスを実装するためにActivityにクラスを作成しました。しかし、New MyActivity().new Listener();を使用する必要があり、getSupportFragmentManager()を使用しようとすると、Exceptionのこのインスタンスが初期化されていないため、Activityがスローされるため、問題が発生しました。

[〜#〜]サード[〜#〜]
次に、Activityにリスナーを直接実装させようとしました。これは、アクティビティではなく、リスナーとの依存関係のみを作成しているためです。しかし今、私はActivityが2〜4の異なるインターフェースを実装するようになり、まとまりが大幅に低下するため、躊躇しています。

ですから、私が試した方法は、レンガの壁にぶつかり、依存関係を作成しているようです。作成する必要があるかどうかはわかりません。私は失敗し、これらのオプションの1つを使用する必要がありますか?もしそうなら、どのオプションが最適でしょうか?どんな助けや提案も大歓迎です。

13
Jason Crosby

個人的には、フラグメントは再利用可能でモジュール式のコンポーネントと見なす必要があると思います。したがって、この再利用性を提供するために、フラグメントは親アクティビティについてあまり知らないはずです。しかし、その見返りとして、活動は彼らが保持している断片について知らなければなりません。

したがって、最初のオプションは、非常に高度に結合されたコードを引き起こすと述べた依存関係の理由から、私の意見では決して考慮されるべきではありません。

2番目のオプションについては、フラグメントは、アプリケーションフローまたはUI関連の決定(新しいフラグメントの表示、フラグメント固有のイベントがトリガーされたときの処理の決定など)を親アクティビティに委任できます。したがって、リスナー/コールバックはフラグメント固有である必要があり、したがってフラグメントで宣言する必要があります。そして、これらのフラグメントを保持するアクティビティは、これらのインターフェイスを実装し、何をするかを決定する必要があります。

したがって、私にとっては3番目のオプションの方が理にかなっています。アクティビティは、特定のコールバックで保持および実行していることに関して、より読みやすいと思います。しかし、そうです、あなたの活動は神の対象になるかもしれません。

複数のインターフェースを実装したくない場合は、Squareの Otto プロジェクトを確認できます。基本的にはイベントバスです。

11
Can Elmas

インターフェースを作成する

public interface ListenFromActivity {
    void doSomethingInFragment();
}

アクティビティクラスListenFromActivityインターフェイスの参照を保持します

 public ListenFromActivity activityListener;   

リスナーを設定するパブリックメソッドを作成する

 public void setActivityListener(ListenFromActivity activityListener) {
        this.activityListener = activityListener;
    }

アクティビティクラスにトリガーポイントを追加します。ここではユーザーインタラクションを使用しました

    @Override
    public void onUserInteraction() {
        super.onUserInteraction();

        if (null != activityListener) {
            activityListener.doSomethingInFragment();
        }
    }

フラグメントクラス

フラグメントにインターフェースクラスを実装させる

public class SomeFragment extends Fragment implements ListenFromActivity

Android Studioは、インターフェースのメソッドをフラグメントで実装するように促します

 void doSomethingInFragment()
{//Add your code here 
}

フラグメントonCreateメソッドでこのようなアクティビティを実行する最後のパーツパーツリスナーインスタンス

((ListnerActivity) getActivity()).setActivityListener(SomeFragment.this);

完了!!。これで、アクティビティからフラグメントメソッドを呼び出すことができます。

11
Hitesh Sahu

FragmentXからFragmentActivityにデータを渡す必要があります。FragmentActivityはこのデータをFragmentYに渡します。これは、フラグメントクラスで定義されたインターフェイスを介して行い、onAttach()で定義されたコールバックをインスタンス化します。

これを行う方法の詳細はこちら 他のフラグメントとの通信

簡単な例として、フラグメントAとフラグメントBについて考えてみます。フラグメントAはリストフラグメントであり、アイテムを選択すると、フラグメントBに表示される内容が変わります。簡単ですね。

最初に、フラグメントAをそのように定義します。

 public class FragmentA extends ListFragment{

   //onCreateView blah blah blah

}

そしてここにフラグメントBがあります

public class FragmentB extends Fragment{

 //onCreateView blah blah blah

}

そして、これが両方を管理する私のFragmentActivityです

public class MainActivity extends FragmentActivity{

//onCreate 
//set up your fragments

}

おそらくあなたはすでにこのようなものを持っているでしょう、今ここにあなたがFragmentA(私たちがいくつかのデータを取得するために必要なリストフラグメント)を変更する方法があります。

    public class FragmentA extends ListFragment implements onListItemSelectedListener, onItemClickListener{

OnListItemSelectedListener mListener;

   //onCreateView blah blah blah



 // Container Activity must implement this interface
    public interface OnListItemSelectedListener {
    public void onListItemSelected(int position);
}


}


  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);

    // This makes sure that the container activity has implemented
    // the callback interface. If not, it throws an exception
    try {
        mListener = (OnListItemSelectedListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement OnListItemSelectedListener");
    }
}


  @Override 
 public void onItemClick(AdapterView<?> parent, View view, int position, long id){


 //Here's where you would get the position of the item selected in the list, and  pass    that position(and whatever other data you need to) up to the activity 
//by way of the interface you defined in onAttach

  mListener.onListItemSelected(position);


}

ここで最も重要な考慮事項は、親アクティビティがこのインターフェイスを実装することです。そうしないと、例外が発生します。正常に実装された場合、リストフラグメント内のアイテムが選択されるたびに、アクティビティにその位置が通知されます。明らかに、任意の数またはタイプのパラメーターを使用してインターフェースを変更できます。この例では、整数位置を渡すだけです。これが少しの人、幸運を明らかにすることを願っています。

3
Jade Byfield

2番目の選択肢は正しい方向に進んでいると思います。

フラグメントで、リスナーインターフェイスを定義します。

class MyFragment ...
{
    public interface IMyFragmentListenerInterface
    {
        void DoSomething();
    }
}

アクティビティにインターフェースを実装させます。

class MyActivity
{
    class MyListener1 implements IMyFragmentListenerInterface { ... }
}

リスナーをフラグメントに渡します。私はフラグメントのコンストラクターでそれを行うのが好きですが、それはフラグメントを完全に自分で管理する場合にのみ機能します。代わりに、フラグメントにsetListenerメソッドを追加できます。

2
zmbq

ただ ドキュメントに従ってください

Fragment

public class HeadlinesFragment extends Fragment {

    // Container Activity must implement this interface
    public interface OnHeadlineSelectedListener {
        public void onArticleSelected(int position);
    }

    OnHeadlineSelectedListener mCallback;

    // "Bind" to the Activity where this Fragment lives
    public void setOnHeadlineSelectedListener(Activity activity) {
        mCallback = (OnHeadlineSelectedListener) activity;
    }

    // ...

    // This will send info to the Activity where the Fragment lives
    private void someOtherFunctionOrListener(int position) {
        mCallback.onArticleSelected(position); // pass info into Activity
    }
}

Activity

public static class MainActivity extends Activity
        implements HeadlinesFragment.OnHeadlineSelectedListener{
    // ...

    @Override
    public void onAttachFragment(Fragment fragment) {
        if (fragment instanceof HeadlinesFragment) {
            HeadlinesFragment headlinesFragment = (HeadlinesFragment) fragment;
            headlinesFragment.setOnHeadlineSelectedListener(this);
        }
    }

    @Override
    public void onArticleSelected(int position) {
        // Call received from Fragment
    }
}
0
Tanasis

このようなものを試しましたか(フラグメントから):

FragmentTransaction ft = 
    getActivity().getSupportFragmentManager().beginTransaction();
Fragment prev = 
    getActivity().getSupportFragmentManager().findFragmentByTag("some_name");
if (prev != null) {
    ft.remove(prev);
}
ft.addToBackStack(null);

DialogFragment dialogFragment = DialogFragmentClass.newInstance();
dialogFragment.show(ft, "some_name");

教えてください、乾杯。

0
LuckyMe

疎結合を最大限に活用するには、SquareのOTTOやGreenRobotのEventBusなどのイベントバスを使用できます。フラグメントは、アクティビティによって処理されるイベントを発生させる可能性があり、その逆も同様です。これのすばらしい点は、コンポーネント(アクティビティ、フラグメント)が相互に何も関係がなく、インターフェイスやコールバックを宣言する必要がないことです。

私はすべてのプロジェクトで使用していますが、堅牢で、パフォーマンスへの影響はほとんどまたはまったくありません(通常の状態)。

0
GabrielWeis