将数据从嵌套片段发送到父片段

Posted

技术标签:

【中文标题】将数据从嵌套片段发送到父片段【英文标题】:Sending data from nested fragments to parent fragment 【发布时间】:2014-06-02 07:18:03 【问题描述】:

我有一个FragmentFR1,其中包含几个NestedFragmentsFRaFRbFRc。这些Nested Fragments 通过在FR1 的布局上按Buttons 进行更改。每个Nested Fragments 中都有几个输入字段;其中包括 EditTextsNumberPickersSpinners 之类的内容。当我的用户完成并填写Nested Fragments 的所有值时,FR1(父片段)有一个提交按钮。

然后我怎样才能从我的NestedFragments 中检索我的值并将它们带入FR1

    在每个 Nested Fragment 中声明并以编程方式处理所有 Views。 父FragmentFR1处理NestedFragments的事务。

我希望这个问题足够清楚,我不确定是否需要发布代码,但如果有人觉得我可以这样做。

编辑 1:

这是我添加Nested Fragments 的方法:

tempRangeButton.setOnClickListener(new View.OnClickListener() 

        @Override
        public void onClick(View v) 

            getChildFragmentManager().beginTransaction()
                    .add(R.id.settings_fragment_tertiary_nest, tempFrag)
                    .commit();

        
    );

    scheduleButton.setOnClickListener(new View.OnClickListener() 

        @Override
        public void onClick(View v) 

            getChildFragmentManager().beginTransaction()
                    .add(R.id.settings_fragment_tertiary_nest, scheduleFrag)
                    .commit();
        
    );

    alertsButton.setOnClickListener(new View.OnClickListener() 

        @Override
        public void onClick(View v) 

            getChildFragmentManager().beginTransaction()
                    .add(R.id.settings_fragment_tertiary_nest, alertsFrag)
                    .commit();

        
    );

    submitProfile.setOnClickListener(new View.OnClickListener() 

        @Override
        public void onClick(View v) 
            constructNewProfile();
        
    );

我的constructNewProfile() 方法需要来自我的Nested Fragments 的值。

public Fragment tempFrag = fragment_profile_settings_temperature
        .newInstance();
public Fragment scheduleFrag= fragment_profile_settings_schedules
            .newInstance();
public Fragment alertsFrag = fragment_profile_settings_alerts
        .newInstance();

以上是指父Fragment的字段;以及它们最初是如何实例化的。

【问题讨论】:

也看看我的问题***.com/questions/70721218/…和***.com/questions/70680327/… 【参考方案1】:

片段之间的数据传递可以通过 FragmentManager 完成。从 Fragment 1.3.0-alpha04 开始,我们可以使用 setFragmentResultListener() 和 setFragmentResult() API 在 Fragment 之间共享数据。

Official Documentation

【讨论】:

【参考方案2】:

回答太晚了,我可以建议在子片段中创建 EditText 对象

EditText tx;

在 Oncreateview 中初始化它。然后为桥创建另一个类,例如

public class bridge
public static EditText text = null; 

现在在父片段中获得它的引用。

EditText childedtx = bridge.text;

现在点击方法获取值

onclick(view v)
childedtx.getText().tostring();

在我的项目中进行了测试,它的工作就像魅力一样。

【讨论】:

【参考方案3】:

您可以在片段之间使用共享数据。

public class SharedViewModel extends ViewModel 
    private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

    public void select(Item item) 
        selected.setValue(item);
    

    public LiveData<Item> getSelected() 
        return selected;
    



public class MasterFragment extends Fragment 
    private SharedViewModel model;
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> 
            model.select(item);
        );
    


public class DetailFragment extends Fragment 
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, item -> 
           // Update the UI.
        );
    

更多信息ViewModel Architecture

【讨论】:

【参考方案4】:

不使用接口,你可以通过下面的方式调用子fragment:

( (YourFragmentName) getParentFragment() ).yourMethodName();

【讨论】:

这应该是接受的答案恕我直言。它是一行代码,完全符合需要。希望我能多点赞 如果可能,您应该避免使用此解决方案。片段的全部意义在于它是 UI 的可重用部分。如果您的子片段包含对父片段的硬编码引用,那么您将失去对子片段的可重用性。这就是接口很棒的原因,父母会选择如何实现它们。 除了懒惰和不正确使用片段之外,这不是一个好的解决方案。如果子 Fragment 知道父 Fragment 是什么类,那么您可能不应该创建子 Fragment,而只需将代码放在父 Fragment 中即可。 @uDevel 有时您必须使用子 Fragment - 假设您希望在父 Fragment 中有标签。在这种情况下,子 Fragment 可能只与父 Fragment 一起工作。我想在这种情况下,单线解决方案很棒。 这不是一个好的解决方案。您的子片段与您的父片段紧密耦合【参考方案5】:

在片段之间传递数据的最佳方式是使用接口。这是您需要做的: 在你嵌套的片段中:

public interface OnDataPass 
    public void OnDataPass(int i);


OnDataPass dataPasser;

@Override
public void onAttach(Activity a) 
    super.onAttach(a);
    dataPasser = (OnDataPass) a;


public void passData(int i) 
    dataPasser.OnDataPass(i);

在你的父片段中:

public class Fragment_Parent extends Fragment implements OnDataPass 
...

    @Override
    public void OnDataPass(int i) 
        this.input = i;
    

    btnOk.setOnClickListener(new OnClickListener() 

        @Override
        public void onClick(View v) 
            Fragment fragment = getSupportFragmentManager().findFragmentByTag("0");
            ((Fragment_Fr1) fragment).passData();
        
    


【讨论】:

onAttach(Activity a) 现已弃用。相反,我实现了onAttach(@NonNull Context context),但dataPasser = (OnDataPass) context; 给了我一个致命的异常:java.lang.ClassCastException: com.myapp.MainActivity 不能转换为 com.myapp.OnDataPass 当我定义时它起作用了:dataPasser = (OnDataPass) getParentFragment();。不好吗?【参考方案6】:

最好的方法是使用接口:

    在嵌套片段中声明一个接口

    // Container Activity or Fragment must implement this interface
    public interface OnPlayerSelectionSetListener
    
        public void onPlayerSelectionSet(List<Player> players_ist);
    
    

    将接口附加到父片段

    // In the child fragment.
    public void onAttachToParentFragment(Fragment fragment)
    
        try
        
            mOnPlayerSelectionSetListener = (OnPlayerSelectionSetListener)fragment;
    
        
        catch (ClassCastException e)
        
              throw new ClassCastException(
                  fragment.toString() + " must implement OnPlayerSelectionSetListener");
        
    
    
    
    @Override
    public void onCreate(Bundle savedInstanceState)
    
        Log.i(TAG, "onCreate");
        super.onCreate(savedInstanceState);
    
        onAttachToParentFragment(getParentFragment());
    
        // ...
    
    

    在按钮点击时调用监听器。

    // In the child fragment.
    @Override
    public void onClick(View v)
    
        switch (v.getId())
        
            case R.id.tv_submit:
                if (mOnPlayerSelectionSetListener != null)
                                
                     mOnPlayerSelectionSetListener.onPlayerSelectionSet(selectedPlayers);
                
                break;
            
        
    

    让你的父片段实现接口。

     public class Fragment_Parent extends Fragment implements Nested_Fragment.OnPlayerSelectionSetListener
     
          // ...
          @Override
          public void onPlayerSelectionSet(final List<Player> players_list)
          
               FragmentManager fragmentManager = getChildFragmentManager();
               SomeOtherNestFrag someOtherNestFrag = (SomeOtherNestFrag)fragmentManager.findFragmentByTag("Some fragment tag");
               //Tag of your fragment which you should use when you add
    
               if(someOtherNestFrag != null)
               
                    // your some other frag need to provide some data back based on views.
                    SomeData somedata = someOtherNestFrag.getSomeData();
                    // it can be a string, or int, or some custom java object.
               
          
     
    

在进行片段交易时添加标签,以便您可以在之后查找它以调用其方法。 FragmentTransaction

这是处理片段和嵌套片段之间通信的正确方法,对于活动和片段几乎相同。 http://developer.android.com/guide/components/fragments.html#EventCallbacks

其实官方还有另外一种方式,就是使用activity result,不过这个已经够用了,也很常用。

【讨论】:

getParentFragment() 仅适用于 API 17+,因此此答案应明确说明,否则不够清楚 @uDevel onAttachFragment(getParentFragment());(在第 2 步中)有什么作用?是在Activity吗? @ShrimpCrackers 可能会有些混淆,因为由于原生 Android 中的 Support Library v24.0.0 或 API 24,Google 工程师引入了一种名为 onAttachFragment(Fragment) 的新方法,它实际上与此答案中的方法略有不同这里。 uDevei 2年前写这个答案时恰好选择了相同的方法名称。需要明确的是:您没有覆盖 Android 框架中的 onAttachFragment(),您是在实现您自己的。 @TonyChan 感谢您澄清困惑。由于谷歌创建了一个同名的新方法,我想用一个更好的方法名称来更新这个答案,但我想不出一个不那么容易混淆的名字。来自谷歌的那个实际上命名不正确,imo。通过阅读它的作用,它应该被称为 onChildFragmentAttached。 将方法名称更新为 onAttachToParentFragment 以避免与 Google 的方法混淆。【参考方案7】:

在获取更好的父片段之前检查instanceOf

if (getParentFragment() instanceof ParentFragmentName) 
  getParentFragment().Your_parent_fragment_method();

【讨论】:

【参考方案8】:

您可以使用getChildFragmentManager() 并找到嵌套片段,获取它们并运行一些方法来检索输入值

【讨论】:

我已经使用 childFragmentManager 最初在我的父片段中提交交易;但是,当我尝试在某些父片段的方法中调用 getChildFragmentManager() 时,它会返回错误。 所以 FR1 有方法 "constructFRaProfile()";我在 FR1 中点击提交后调用它。我应该调用 childFragmentManager().findFragmentByTag("FRa"); 吗?然后开始检索值? 我不确定我是否正确设置了标签; android是自动为子fragment设置标签还是必须手动设置? 您是如何使用您的子片段的?从代码添加或在 XML 布局中使用它们 @Jedil 你不能在 XML 中添加子片段,它们必须以编程方式添加

以上是关于将数据从嵌套片段发送到父片段的主要内容,如果未能解决你的问题,请参考以下文章

如何将数据从 BottomSheetDialogFragment 返回到父片段

将数据从活动发送到片段android工作室[重复]

将数据从一个片段发送到另一个片段时出错。 (两个片段都由一个活动托管)

将数据从片段发送到活动,无需任何事件处理或侦听器

如何将字符串数据从活动发送到片段?

需要解释从适配器发送数据到片段