如何将数据从DialogFragment发送到片段?

时间:2013-09-02 19:21:32

标签: java android android-fragments

我有一个片段打开Dialogfragment来获取用户输入(字符串和整数)。如何将这两件事发回片段?

这是我的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 个答案:

答案 0 :(得分:83)

注意:除了一个或两个Android Fragment特定的调用之外,这是一个通用的方法配方,用于在松散耦合的组件之间实现数据交换。您可以安全地使用此方法在字面上的任何内容之间交换数据,无论是片段,活动,对话还是应用程序的任何其他元素。


这是食谱:

  1. 创建interface(即名为MyContract),其中包含传递数据的方法签名,即methodToPassData(... data);
  2. 确保合同的DialogFragment fullfils(通常意味着实现所需的界面):class MyFragment extends Fragment implements MyContract {....}
  3. 创建DialogFragment时,通过调用Fragment将您的myDialogFragment.setTargetFragment(this, 0);设为target fragment。这是您稍后将要讨论的对象。
  4. DialogFragment中,通过调用getTargetFragment();获取该调用片段,并将返回的对象强制转换为您在步骤1中创建的合同接口,方法是执行:MyContract mHost = (MyContract)getTargetFragment();。使用Casting可以确保目标对象实现所需的合同,我们可以期待methodToPassData()存在。如果没有,那么您将获得常规ClassCastException。这通常不应该发生,除非你做了太多的复制粘贴编码:)如果你的项目使用外部代码,库或插件等,在这种情况下你应该捕获异常并告诉用户即插件不兼容而不是让app崩溃。
  5. 当发送数据的时间到来时,请在之前获得的对象上调用methodToPassData()((MyContract)getTargetFragment()).methodToPassData(data);。如果您的onAttach()已经投射并将目标片段分配给类变量(即mHost),那么此代码将只是mHost.methodToPassData(data);
  6. 瞧。
  7. 您刚刚将对话框中的数据成功传递回调用片段。

答案 1 :(得分:35)

这是另一种不使用任何界面的食谱。只需使用setTargetFragmentBundle在DialogFragment和Fragment之间传递数据。

public static final int DATEPICKER_FRAGMENT = 1; // class variable

1。 拨打DialogFragment,如下所示:

// create dialog fragment
DatePickerFragment dialog = new DatePickerFragment();

// optionally pass arguments to the dialog fragment
Bundle args = new Bundle();
args.putString("pickerStyle", "fancy");
dialog.setArguments(args);

// setup link back to use and display
dialog.setTargetFragment(this, DATEPICKER_FRAGMENT);
dialog.show(getFragmentManager().beginTransaction(), "MyProgressDialog")

2。 使用BundleIntent中的额外DialogFragment将任何信息传递回目标片段。 Button#onClick() DatePickerFragment事件中的以下代码传递字符串和整数。

Intent i = new Intent()
        .putExtra("month", getMonthString())
        .putExtra("year", getYearInt());
getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, i);
dismiss();

3。 使用CalendarFragment的{​​{1}}方法读取值:

onActivityResult()

答案 2 :(得分:0)

一个好的技巧是使用ViewModel和LiveData方法,这是最好的方法。贝娄是有关如何在片段之间共享数据的代码示例:

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

答案 3 :(得分:0)

这是说明Marcin用kotlin实现答案的方法。

1。创建一个接口,该接口具有用于在dialogFragment类中传递数据的方法。

interface OnCurrencySelected{
    fun selectedCurrency(currency: Currency)
}

2。将接口添加到dialogFragment构造函数中。

class CurrencyDialogFragment(val onCurrencySelected :OnCurrencySelected)    :DialogFragment() {}

3。现在让您的Fragment实现您刚刚创建的接口

class MyFragment : Fragment(), CurrencyDialogFragment.OnCurrencySelected {

override fun selectedCurrency(currency: Currency) {
//this method is called when you pass data back to the fragment
}}

4。然后显示您的对话框 CurrencyDialogFragment(this).show(fragmentManager,"dialog")this是您将要与之交谈的接口对象,用于将数据传递回Fragment。

5。当您想将数据发送回Fragment时,只需调用该方法即可将数据传递给您在dialogFragment构造函数中传递的接口对象。

onCurrencySelected.selectedCurrency(Currency.USD)
dialog.dismiss()