在实例化时将对象传递给 Fragment 或 DialogFragment

Posted

技术标签:

【中文标题】在实例化时将对象传递给 Fragment 或 DialogFragment【英文标题】:Passing an Object to Fragment or DialogFragment upon Instantiation 【发布时间】:2013-04-30 15:01:55 【问题描述】:

我正在尝试找出在不违反“empty constructor”规则的情况下将对象传递给Fragment 或DialogFragment 的正确方法。

例如,我创建了一个自定义视图,并为每个我实例化的视图关联一个 DiaglogFragment。此 DialogFragment 将用于显示控件,用户可以使用这些控件更改与其关联的自定义 View 的某些方面。因为 View 是一个我知道我不能使用 setArguments() 的对象。

我可以实现我的 DialogFragment 的 newInstance(View) 方法,即工厂模式,但是如果我的 Fragment 被系统保存然后在以后恢复会发生什么?据我所知,不会有对 View 对象的引用?

有人能告诉我我是否以错误的方式使用 Fragment,或者是否有办法实现将对象传递给 Fragment,这也将处理系统在以后重建它。

【问题讨论】:

向你的片段添加一个setter,然后在new Fragment()之后调用那个setter?但是您不想设置视图。您想告诉片段它需要显示什么,并且它应该能够自己提出视图。如果活动正在做这项工作,那么这可能意味着您没有正确拆分片段和活动。 片段不会显示视图,它只是与其密切相关。然而 Fragment 需要将数据传回给 View(比如选择了哪个 Radio 按钮) 正确的做法是创建一个接口,让活动实现并且片段可以调用方法。基本上,活动应该协调活动中片段和其他视图之间的任何交互。 是的,你让我意识到我正在以不应该的方式使用 Fragments。我能做的是传入视图的 id 以及包含该视图的片段。需要时,我的 DialogFragment 可以回调包含 Activity 以传递数据。 【参考方案1】:

在您的 DialogFragmnet 类中,您创建了两个方法:

    newInstance 创建您的 DialogFragment 的实例

    setter 来初始化你的对象

并在onCreate 中添加setRetainInstance(true);

public class YourDialogFragment extends DialogFragment 

    ComplexVariable complexVar;

    public static YourDialogFragment newInstance(int arg, ComplexVariable complexVar) 
        YourDialogFragment frag = new MoveSongDialogFragment();
        Bundle args = new Bundle();
        args.putInt("count", arg);
        frag.setArguments(args);
        frag.setComplexVariable(complexVar);
        return frag;
    

    public void setComplexVariable(ComplexVariable complexVar) 
        this.complexVar = complexVar;
    

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    

然后,显示对话框

FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();

Fragment prev = manager.findFragmentByTag("yourTag");
if (prev != null) 
    ft.remove(prev);


// Create and show the dialog.
DialogFragment newFragment = YourFragmentDialog.newInstance(argument, yourComplexObject);
newFragment.show(ft, "yourTag");

【讨论】:

不确定这是一个好方法,因为您的 DialogFragment 可以自动恢复(例如在旋转期间),然后 yourVar 值将为空。所以DialogFragment在系统自动实例化的情况下会渲染不正确。 似乎将序列化对象放在 Fragment 的 args 中是唯一好的解决方案。或者使用 getActivity()+interface 方法进行标准通信。 @goRGon 你是对的,如果你没有调用片段的 onCreate setRetainInstance(true); 更新了答案并添加了 setRetainInstance(true);供日后参考 或将复杂的变量存储在架构组件 ViewModel 中【参考方案2】:

您可以将 Bundle extras 中的 Object 作为 Parcelable Objects (http://developer.android.com/reference/android/os/Parcelable.html ) 传递,并将它们传递给 onCreateView(Bundle savedInstanceState) 中的 Bundle。如果用户翻转屏幕,您可以保存它们。

编辑: this Parcelable 教程相当不错!

另一种方法是从您的 ParentActivity 获取数据对象,但我不确定这是否是一种好方法(但它有效..)

@Override
public void onActivityCreated(Bundle savedInstanceState) 
    super.onActivityCreated(savedInstanceState);
    mYourObject = ((MainActivity) getActivity()).getYourObject();

您必须为此在 Activity 中创建一个 Getter

public YourObject getYourObject()
   return mYourObecjt;

但我认为 Parcelables 是更好的方法,因为您可以在没有任何依赖关系的情况下重用您的 Fragments...

【讨论】:

不确定 Parcelable 是我需要的,但在阅读了链接后,我意识到我可能没有明确我的问题。我需要一个对实际对象的引用。 Parcelable 对象是实际对象的重建/克隆?我需要参考,以便实时更改视图。【参考方案3】:

您总是可以使用像 GSON 或 Genson 这样的优秀 JSON 库来序列化对象 - 这是我对任何远程复杂对象的 goto 方法。对于简单的操作,GSON 稍微紧凑一些,但如果您的视图中有任何类型的继承/多态性,我强烈推荐 Genson。只要您记录它们,就可以有一个带参数的 ctr。

https://code.google.com/p/genson/ - 在下载部分获取 JAR。

【讨论】:

感谢您的回复。我意识到我只需要对实际对象的引用,因此任何形式的序列化都会使事情变得复杂。我只需要通过既定方式的活动进行交流。【参考方案4】:

我通过 sharepreference 解决了我的需求。 YuzdeDataUser 是我的自定义类,我从我的列表视图中获取它的 onClickItemListener

如何发送

  YuzdeDataUser clickedObj = (YuzdeDataUser) parent.getItemAtPosition(position);
            //clickedObj.setTarihim();
            SharedPreferences shp = getSharedPreferences("sam", MODE_PRIVATE);
            SharedPreferences.Editor editor = shp.edit();

            Gson gson = new Gson();
            String json = gson.toJson(clickedObj);
            editor.putString("yoklamaList", json);
            editor.commit();

            FragmentManager fragmentManager = getSupportFragmentManager();
            AylikRaporPop userPopUp = new AylikRaporPop();
            userPopUp.show(fragmentManager, "sam");

如何接收

    SharedPreferences shp = parent.getSharedPreferences("sam", MODE_PRIVATE);
    SharedPreferences.Editor editor = shp.edit();

    Gson gson = new Gson();
    String json = shp.getString("yoklamaList", "");
    YuzdeDataUser user = gson.fromJson(json, YuzdeDataUser.class);
    if (user != null) 
        txt_ad.setText(user.getAd());
        txt_tur_tarih.setText(Util.getInstance(parent).writeNameOfTur(user.getTur_id()));
        txt_var.setText("" + user.getVar());
        txt_gorevli.setText("" + user.getGorevli());
        txt_yok.setText("" + user.getYok());

    

【讨论】:

以上是关于在实例化时将对象传递给 Fragment 或 DialogFragment的主要内容,如果未能解决你的问题,请参考以下文章

Java/Android - 在资源打开的情况下将对象传递给方法

在Kotlin中,如果将对象传递给类的新实例,然后更改某些属性,它是否会在原始对象中更改?

如何将对象传递给 C++ 中的函数?

如何按值将对象传递给Angular2 +组件

尝试将对象传递给同一个模板类进行复制

将对象传递给 Java 中的不同库