50

Dialogfragmentユーザー入力(文字列と整数)を取得するためにa を開くフラグメントがあります。これら 2 つのものをフラグメントに戻すにはどうすればよいですか?

ここに私のDialogFragmentがあります:

public class DatePickerFragment extends DialogFragment {
    String Month;
    int Year;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        getDialog().setTitle(getString(R.string.Date_Picker));
        View v = inflater.inflate(R.layout.date_picker_dialog, container, false);

        Spinner months = (Spinner) v.findViewById(R.id.months_spinner);
        ArrayAdapter<CharSequence> monthadapter = ArrayAdapter.createFromResource(getActivity(),
                R.array.Months, R.layout.picker_row);
              months.setAdapter(monthadapter);
              months.setOnItemSelectedListener(new OnItemSelectedListener(){
                  @Override
                  public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int monthplace, long id) {
                      Month = Integer.toString(monthplace);
                  }
                  public void onNothingSelected(AdapterView<?> parent) {
                    }
              });

        Spinner years = (Spinner) v.findViewById(R.id.years_spinner);
        ArrayAdapter<CharSequence> yearadapter = ArrayAdapter.createFromResource(getActivity(),
             R.array.Years, R.layout.picker_row);
        years.setAdapter(yearadapter);
        years.setOnItemSelectedListener(new OnItemSelectedListener(){
          @Override
          public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int yearplace, long id) {
              if (yearplace == 0){
                  Year = 2012;
              }if (yearplace == 1){
                  Year = 2013;
              }if (yearplace == 2){
                  Year = 2014;
              }
          }
          public void onNothingSelected(AdapterView<?> parent) {}
        });

        Button button = (Button) v.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
           public void onClick(View v) {
               getDialog().dismiss();
            }
        });

        return v;
    }
}

ボタンをクリックした後、その前にデータを送信する必要がありますgetDialog().dismiss()

データを送信する必要があるフラグメントは次のとおりです。

public class CalendarFragment extends Fragment {
int Year;
String Month;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    int position = getArguments().getInt("position");
    String[] categories = getResources().getStringArray(R.array.categories);
    getActivity().getActionBar().setTitle(categories[position]);
    View v = inflater.inflate(R.layout.calendar_fragment_layout, container, false);    

    final Calendar c = Calendar.getInstance();
    SimpleDateFormat month_date = new SimpleDateFormat("MMMMMMMMM");
    Month = month_date.format(c.getTime());
    Year = c.get(Calendar.YEAR);

    Button button = (Button) v.findViewById(R.id.button);
    button.setText(Month + " "+ Year);
    button.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
           new DatePickerFragment().show(getFragmentManager(), "MyProgressDialog");
        }
    });
   return v;
  }
}

そのため、ユーザーが で日付を選択するDialogfragmentと、月と年を返す必要があります。

次に、ボタンのテキストが、ユーザーが指定した月と年に変更されます。

4

4 に答える 4

96

注: 1 つまたは 2 つの Android Fragment 固有の呼び出しは別として、これは疎結合コンポーネント間のデータ交換を実装するための一般的なレシピです。このアプローチを使用して、フラグメント、アクティビティ、ダイアログ、またはアプリケーションのその他の要素など、文字通り何でも安全にデータを交換できます。


レシピは次のとおりです。

  1. データを渡すためのメソッドの署名を含む作成interface(つまり名前付き)、つまり.MyContractmethodToPassMyData(... data);
  2. DialogFragmentfullfils がコントラクトすることを確認します(これは通常、インターフェースを実装することを意味します)。class MyFragment extends Fragment implements MyContract {....}
  3. の作成時に、 を呼び出して、呼び出しをターゲット フラグメントDialogFragmentとして設定します。これは、後で話すオブジェクトです。FragmentmyDialogFragment.setTargetFragment(this, 0);
  4. DialogFragmentで、呼び出しフラグメントを呼び出して取得し、返さgetTargetFragment();れたオブジェクトを手順 1 で作成したコントラクト インターフェイスにキャストしますMyContract mHost = (MyContract)getTargetFragment();。キャストにより、ターゲット オブジェクトが必要なコントラクトを実装していることを確認でき、そこにいることが期待できmethodToPassData()ます。そうでない場合は、定期的に取得しますClassCastException。これは通常、コピーと貼り付けのコーディングをあまり行わない限り、発生しないはずです:) プロジェクトで外部コード、ライブラリ、プラグインなどを使用している場合は、例外をキャッチして、プラグインが互換性がないことをユーザーに伝える必要があります。アプリをクラッシュさせます。
  5. データを送り返す時が来たら、methodToPassMyData()以前に取得したオブジェクトを呼び出します: ((MyContract)getTargetFragment()).methodToPassMyData(data);. onAttach()すでにターゲット フラグメントをキャストしてクラス変数 (つまり ) に割り当てている場合mHost、このコードは単にmHost.methodToPassMyData(data);.
  6. ほら。ダイアログからフラグメントの呼び出しにデータを正常に渡しました。
于 2013-09-02T19:25:46.130 に答える
3

良いヒントは、最良の方法であるViewModelandアプローチを使用することです。以下は、 sLiveData間でデータを共有する方法に関するコード サンプルです。Fragment

class SharedViewModel : ViewModel() {
    val selected = MutableLiveData<Item>()

    fun select(item: Item) {
        selected.value = item
    }
}

class MasterFragment : Fragment() {

    private lateinit var itemSelector: Selector

    private lateinit var model: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        model = activity?.run {
            ViewModelProviders.of(this).get(SharedViewModel::class.java)
        } ?: throw Exception("Invalid Activity")
        itemSelector.setOnClickListener { item ->
            // Update the UI
        }
    }
}

class DetailFragment : Fragment() {

    private lateinit var model: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        model = activity?.run {
            ViewModelProviders.of(this).get(SharedViewModel::class.java)
        } ?: throw Exception("Invalid Activity")
        model.selected.observe(this, Observer<Item> { item ->
            // Update the UI
        })
    }
}

試してみてください。これらの新しいコンポーネントが役に立ちます。他のアプローチよりも効率的だと思います。

詳細については、https ://developer.android.com/topic/libraries/architecture/viewmodel をご覧ください。

于 2018-11-01T21:52:18.167 に答える