簡體   English   中英

如何將數據從 DialogFragment 發送到 Fragment?

[英]How to send data from DialogFragment to a Fragment?

我有一個片段,它打開一個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選擇了一個日期,它必須返回月份和年份。

然后,按鈕上的文本應更改為用戶指定的月份和年份。

注意:除了一兩個 Android Fragment 特定調用之外,這是實現松散耦合組件之間數據交換的通用方法。 您可以安全地使用這種方法在任何東西之間交換數據,無論是片段、活動、對話框還是應用程序的任何其他元素。


這是食譜:

  1. 創建包含傳遞數據的方法簽名的interface (即名為MyContract ),即methodToPassMyData(... data); .
  2. 確保您的DialogFragment滿足該合同(這通常意味着實現接口): class MyFragment extends Fragment implements MyContract {....}
  3. 在創建DialogFragment通過調用myDialogFragment.setTargetFragment(this, 0);將調用Fragment設置為其目標片段myDialogFragment.setTargetFragment(this, 0); . 這是您稍后將要與之交談的對象。
  4. 在您的DialogFragment ,通過調用getTargetFragment();獲取該調用片段getTargetFragment(); 並將返回的對象MyContract mHost = (MyContract)getTargetFragment();您在第 1 步中創建的合約接口,方法是: MyContract mHost = (MyContract)getTargetFragment(); . 轉換讓我們確保目標對象實現所需的契約,我們可以期待methodToPassData()存在。 如果沒有,那么您將收到常規ClassCastException 這通常不應該發生,除非你做了太多的復制粘貼編碼:) 如果你的項目使用外部代碼、庫或插件等,在這種情況下你應該捕捉異常並告訴用戶即插件不兼容而不是讓應用程序崩潰。
  5. 當返回數據的時間到來時,對之前獲得的對象調用methodToPassMyData()((MyContract)getTargetFragment()).methodToPassMyData(data); . 如果您的onAttach()已經將目標片段轉換並分配給一個類變量(即mHost ),那么此代碼將只是mHost.methodToPassMyData(data); .
  6. 瞧。 您剛剛成功地將對話框中的數據傳遞回調用片段。

這是另一個不使用任何接口的方法。 只是利用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. 在DialogFragmentIntent中使用額外的Bundle將任何信息傳遞回目標片段。 DatePickerFragment Button#onClick()事件中的以下代碼傳遞一個字符串和整數。

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

3. 使用CalendarFragmentonActivityResult()方法讀取值:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case DATEPICKER_FRAGMENT:
            if (resultCode == Activity.RESULT_OK) {
                Bundle bundle = data.getExtras();
                String mMonth = bundle.getString("month", Month);
                int mYear = bundle.getInt("year");
                Log.i("PICKER", "Got year=" + year + " and month=" + month + ", yay!");
            } else if (resultCode == Activity.RESULT_CANCELED) {
                ...
            }
            break;
    }
}

這是一種說明 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.然后顯示你的 dialogFragment 你只需調用CurrencyDialogFragment(this).show(fragmentManager,"dialog") this是您將與之交談的接口對象,用於將數據傳回您的 Fragment。

5.當您想將數據發送回您的 Fragment 時,您只需調用該方法以在您在 dialogFragment 構造函數中傳遞的接口對象上傳遞數據。

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

一個很好的提示是使用ViewModelLiveData方法,這是最好的方法。 Bellow 是關於如何在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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM