フラグメントとそのコンテナアクティビティの間でデータを受け渡す


176

フラグメントとそのコンテナアクティビティの間でデータを渡すにはどうすればよいですか?インテントを介してアクティビティ間でデータを渡すことに似たものはありますか?

私はこれを読みましたが、あまり役に立ちませんでした:http :
//developer.android.com/guide/topics/fundamentals/fragments.html#CommunicatingWithActivity


それは不十分ですか?あなたはあなたが望むものを送ることができます、おそらくあなたはもっと説明することができます、あなたは何を達成したいですか?
Marcin Milejski、2012

ドキュメントから、たとえば、アクティビティからフラグメントに、またはその逆に、値または文字列を渡す方法がわかりませんでした。ありがとう
tyb

2
フラグメントからの非同期呼び出しを処理してデータを返す最良の方法は、両側にBroadcastReceiversを実装することです。特定でない数のフラグメントで作業している場合は、とにかく非同期にする必要があります。
Marek Sebera 2013

@punisher_maladeいいえ、私のために機能します
Vadim Kotov

回答:


211

フラグメントでは、を呼び出すことができますgetActivity()

これにより、フラグメントを作成したアクティビティにアクセスできるようになります。そこから、アクティビティ内にあるあらゆる種類のアクセサメソッドを呼び出すことができます。

たとえばgetResult()、アクティビティで呼び出されるメソッドの場合:

((MyActivity) getActivity()).getResult();

86
(親のAndroidアクティビティではなく)YOURアクティビティ内の関数にアクセスしているので、getActivity()呼び出しをキャストする必要があります:((MyActivity)getActivity())。getResult();
Nick

3
フラグメントからアクティビティまで、おそらくどのようにbackメソッドになるでしょうか?
Vasil

6
@VasilValchevでは、インターフェースを作成し、アクティビティにそれを実装させ、フラグメント内からメソッドを呼び出してデータを渡すことができます。onAttachメソッドを使用して、アクティビティがインターフェースを実装しているかどうかを確認します。
Ivan Nikolov 2013年

3
@IvanNikolovからのすばらしい回答。詳細な説明はFragments Training Link
bogdan

8
これは良い習慣でもパターンでもありません。インターフェースでの答えは正しいものです。
moictab 2018年

303

インターフェイスを使用してみてください。

データを含むアクティビティにデータを返す必要があるフラグメントは、データを処理して渡すためのインターフェースを宣言する必要があります。次に、包含アクティビティがこれらのインターフェースを実装していることを確認します。例えば:

JAVA

フラグメントで、インターフェースを宣言します...

public interface OnDataPass {
    public void onDataPass(String data);
}

次に、インターフェースの包含クラスの実装を、次のようにonAttachメソッドのフラグメントに接続します。

OnDataPass dataPasser;

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    dataPasser = (OnDataPass) context;
}

フラグメント内で、データの受け渡しを処理する必要がある場合は、dataPasserオブジェクトで呼び出すだけです。

public void passData(String data) {
    dataPasser.onDataPass(data);
}

最後に、実装する アクティビティOnDataPass ...

@Override
public void onDataPass(String data) {
    Log.d("LOG","hello " + data);
}

コトリン

ステップ1.インターフェイスを作成する

interface OnDataPass {
    fun onDataPass(data: String)
}

ステップ2.次に、インターフェースの包含クラスの実装を、次のようにonAttachメソッド(YourFragment)のフラグメントに接続します。

lateinit var dataPasser: OnDataPass

override fun onAttach(context: Context) {
    super.onAttach(context)
    dataPasser = context as OnDataPass
}

ステップ3.フラグメント内で、データの受け渡しを処理する必要がある場合は、dataPasserオブジェクトで呼び出すだけです。

fun passData(data: String){
    dataPasser.onDataPass(data)
}

ステップ4.最後に、アクティビティにOnDataPassを実装します

class MyActivity : AppCompatActivity(), OnDataPass {}

override fun onDataPass(data: String) {
    Log.d("LOG","hello " + data)
}

1
要は正解です。これもここで非常にうまく説明されてます。私が気づかなかったことは、複数のインターフェースを実装できることです。私はすでにを実装してActionBar.TabListenerおり、インターフェースを追加する必要がありました。
Eugene van der Merwe 2012

5
これは間違いなく進むべき道であり、私の意見では、唯一の進むべき道です。また、アクティビティとフラグメント間の双方向の相互作用を提供します。また、タブまたはマルチフラグレイアウトを介して、1つのアクティビティに複数のフラグメントがある場合に、フラグメント間で通信する手段を提供します。
クリストファー

1
何か不思議に思っています...これは公式の回答です。公式の開発者サイトから、これはfrag-act-fragを伝達する正しい方法であると言われていますが、なぜgetActivity( )?
unmultimedio 2014年

3
なぜ誰かがそれを行うために追加のインターフェースを必要とするのですか?次の解決策を悪いと思うのはなぜですか?((MyActivity)getActivity).myMethod(...)
spacifici '10

3
onAttach(Activity activity)は非推奨です。代わりにonAttach(Context context)を使用してください。
Chris.C、2016年

23

最も簡単なアプローチですが推奨されません

フラグメントからアクティビティデータにアクセスできます。

アクティビティ:

public class MyActivity extends Activity {

    private String myString = "hello";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        ...
    }

    public String getMyData() {
        return myString;
    }
}

断片:

public class MyFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        MyActivity activity = (MyActivity) getActivity();
        String myDataFromActivity = activity.getMyData();
        return view;
    }
}

5
これにより、コードに高度な結合が追加され、悪い習慣になります。これで、フラグメントを以外のアクティビティで使用できなくなりますMyActivity
AmeyaB

なぜこの方法が悪い習慣と見なされ、インターフェースがこの質問の唯一の解決策であるのですか?
androidXP 2017年

AmeyaBすべてのアクティビティがBaseActivityから拡張されている場合、またはBaseActivityアクティビティのようにキャストする場合=(BaseActivity)getActivity(); その後、すべてのアクティビティで機能します
Zar E Ahmer '19年

21
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    Bundle b = getActivity().getIntent().getExtras();
            wid = b.getString("wid");
            rid = b.getString("rid");
            View view = inflater.inflate(R.layout.categoryfragment, container, false);
    return view;
 }

14
これはフラグメントで取得する方法ですが、XMLレイアウトファイルにフラグメントがある場合、フラグメントを呼び出すクラスでどのように設定しますか。
Zapnologica 2013

17

フラグメントとそのコンテナアクティビティの間でデータを受け渡す

アクティビティ:

        Bundle bundle = new Bundle();
        bundle.putString("message", "Alo Elena!");
        FragmentClass fragInfo = new FragmentClass();
        fragInfo.setArguments(bundle);
        transaction.replace(R.id.fragment_single, fragInfo);
        transaction.commit();

断片:

フラグメントの値を読み取る

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        String myValue = this.getArguments().getString("message");
        ...
        ...
        ...
        }

@Elenasys様、こんにちは。アクティビティからフラグメントにバンドルデータを送信するにはどうすればよいですか。フラグメントからアクティビティに移動し、既に作成されているフラグメントに戻る必要があります(onStart、onResumeなどを呼び出すだけです)。アクティビティで取得できたデータが必要です。それを行う方法はありますか、それとも何か間違っていますか?
Michal Moravik、

7

これが最善の方法かどうかわかりませんが、Buをフラグメントからコンテナアクティビティに渡す方法を見つけるためにGoogleでかなり長い間検索してきましたが、代わりにアクティビティからフラグメントにデータを送信するだけでした。 (私は初心者なので、少し混乱しました)。

後で私は自分の好きなものを試しました。ここに投稿します。私のような人が同じものを探しています。

// Fragmentからデータを渡します。

Bundle gameData = new Bundle();
        gameData.putStringArrayList(Constant.KEY_PLAYERS_ARR,players);
        gameData.putString(Constant.KEY_TEAM_NAME,custom_team_name);
        gameData.putInt(Constant.KEY_REQUESTED_OVER,requestedOver);

        Intent intent = getActivity().getIntent();
        intent.putExtras(gameData);

//コンテナのアクティビティからバンドルからデータを取得します。

Bundle gameData = getIntent().getExtras();
        if (gameData != null)
        {
            int over = gameData.getInt(Constant.KEY_REQUESTED_OVER);
            ArrayList<String> players = gameData.getStringArrayList(Constant.KEY_PLAYERS_ARR);
            String team = gameData.getString(Constant.KEY_TEAM_NAME);

        }
        else if (gameData == null)
        {
            Toast.makeText(this, "Bundle is null", Toast.LENGTH_SHORT).show();
        }

6

インターフェイスは最高のソリューションの1つです。

接着インターフェース:

public interface DataProviderFromActivity {

    public String getName();
    public String getId);

}  

MyActivity:

public class MyActivity implements DataProviderFromActivity{

    String name = "Makarov";
    String id = "sys533";

    ... ... ... ... ... .... .... 
    ... ... ... ... ... .... .... 

    public String getName(){
        return name;
    };
    public String getId(){
        return id;
    };
}

MyFragment:

public class MyFragment extends Fragment{

    String fragName = "";
    String fragId = "";

    ... ... ... ... ... .... .... 
    ... ... ... ... ... .... .... 

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        DataProviderFromActivity myActivity= (DataProviderFromActivity) getActivity();
        fragName = myActivity.getName();
        fragId = myActivity.getId();

        ... ... ... ... ... .... .... 
        ... ... ... ... ... .... .... 

        updateFragmentView();
    }
}

こんにちは@HassanMakarovシンプルでクリーンなインターフェースが好きです。私には問題が1つあります。私のビューページャーに固有のものかどうかはわかりませんが、一度に取得できるのは最大2つのフラグメントのみです。文字列「Makarov」と「sys533」は、アクティビティの作成時にフラグメント1と2に表示されますが、フラグメント2または3が選択されるまで、文字列はフラグメント3に表示されませんか?何か案は?
JC23 2017

@ JC23問題はフラグメントトランザクションに関連していると思います。MainActivityの起動時に設定されるフラグメントはどれですか?
Hassan Tareq 2017

@ JC23私がやっていること:Tab / ViewPagerの代わりにToolbarとNavigationViewを使用しています。onNavigationItemSelected()でフラグメントトランザクションを実行して、それに応じてフラグメントを設定します。
Hassan Tareq 2017

2

日付リスナーを実装するAppCompatActivityを使用しました。私は日付範囲セレクターをコーディングする必要があったので、フラグメントは必要として来ました。また、選択した日付を受け取って親アクティビティに戻すためのコンテナーも必要でした。

コンテナアクティビティの場合、これはクラス宣言です。

public class AppCompatDateRange extends AppCompatActivity implements
    DateIniRangeFragment.OnDateIniSelectedListener, DateFimRangeFragment.OnDateFimSelectedListener

そして、コールバックのインターフェース:

@Override
public void onDateIniSelected(String dataIni) {
    Log.i("data inicial:", dataIni);
}

@Override
public void onDateFimSelected(String dataFim) {
    Log.i("data final:", dataFim);
}

日付はクエリ選択のパラメータであるため、コールバックは文字列です。

フラグメントのコード(最初の日付フラグメントに基づく):

public class DateIniRangeFragment extends Fragment {
OnDateIniSelectedListener callbackIni;

private DatePicker startDatePicker;

public DateIniRangeFragment() {
    ///required empty constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

///through this interface the fragment sends data to the container activity
public interface OnDateIniSelectedListener {
    void onDateIniSelected(String dataIni);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    ///layout for the fragment
    View v = inflater.inflate(R.layout.date_ini_fragment, container, false);

    ///initial date for the picker, in this case, current date
    startDatePicker = (DatePicker) v.findViewById(R.id.start_date_picker_appcompat);
    Calendar c = Calendar.getInstance();
    int ano = c.get(Calendar.YEAR);
    int mes = c.get(Calendar.MONTH);
    int dia = c.get(Calendar.DAY_OF_MONTH);
    startDatePicker.setSpinnersShown(false);
    startDatePicker.init(ano, mes, dia, dateSetListener);

    return v;
}

///listener that receives the selected date
private DatePicker.OnDateChangedListener dateSetListener = new DatePicker.OnDateChangedListener() {
    public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
        if (view.isShown()) { ///if the datepicker is on the screen
            String sDataIni = year + "-" + (monthOfYear + 1) + "-" + dayOfMonth;
            callbackIni.onDateIniSelected(sDataIni); //apply date to callback, string format
        }
    }
};

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

    /*
    * this function guarantees that the container activity implemented the callback interface
    * */
    try {
        callbackIni = (OnDateIniSelectedListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString() + " deve implementar OnDateIniSelectedListener");
    }
}

}

コンテナー+フラグメントを構成するために、FragmentPagerAdapterを拡張するカスタムクラスでViewPager(AppCompat)を使用しました。ダイアログはありません。


2

単にあなたが使用することができますEventBusを、それは簡単で、作業素晴らしいです

3ステップのEventBus

  1. イベントを定義します。

    public static class MessageEvent { /* Additional fields if needed */ }

  2. サブスクライバーの準備:サブスクライブメソッドを宣言して注釈を付け、オプションでスレッドモードを指定します。

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent event) {/* Do something */};

サブスクライバーを登録および登録解除します。たとえばAndroidでは、アクティビティとフラグメントは通常、ライフサイクルに従って登録する必要があります。

 @Override
 public void onStart() {
     super.onStart();
     EventBus.getDefault().register(this);
 }

 @Override
 public void onStop() {
     super.onStop();
     EventBus.getDefault().unregister(this);
 }
  1. イベントを投稿:

    EventBus.getDefault().post(new MessageEvent());


1

これは遅いかもしれないことを知っています。しかし、私も常にこの質問に迷っていました。私はこのリンクを共有しています...これはおそらくこれが私がこれについてウェブで見つけた最も良い説明であるためです。これはFragment to ActivityおよびFragment to Fragmentを解決します!

本当によく解かれ説明された


0

これは私のために働いています。

アクティビティでこのメソッドを追加します

    public void GetData(String data)
     {
        // do something with your data        
     }

とフラグメントでこの行を追加します

((YourActivity)getContext).GetData("your data here");

0
public class Fragmentdemo extends Fragment {

  public interface onDemoEventListener {
    public void demoEvent(String s);
  }

  onDemoEventListener demoEventListener;

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
        try {
          demoEventListener = (onDemoEventListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement onDemoEventListener");
        }
  }

  final String LOG_TAG = "TAG";

  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragmentdemo, null);

    Button button = (Button) v.findViewById(R.id.button);
    button.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        demoEventListener.someEvent("Test text to Fragment1");
      }
    });
    enter code here
    return v;
  }
}

-12

別のアクティビティから渡されたデータを、コンテナアクティビティのフラグメントで取得する別の簡単な方法:

Activity_A => Activity_B(フラグメント)

Activity_Aで、別のアクティビティにデータ(ここでは文字列)を送信するようなインテントを作成します。

Intent intent = new Intent(getBaseContext(),Activity_B.class);
intent.putExtra("NAME", "Value");
startActivity(intent);

あなたのフラグメントで、あなたのActivity_Bに含まれています:

String data = getActivity().getIntent().getExtras();

getBaseContext()次のエラーが表示されます:The method getBaseContext() is undefined for the type new View.OnClickListener(){}
Si8
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.