从Activity向Fragment传递一个对象

86

我有一个使用了FragmentActivity。我想从这个Activity将一个对象传递给Fragment

我该如何做呢? 到目前为止,我看到的所有教程都是从资源中检索数据。

编辑:

让我们再具体一些:

我的Activity在左侧有一个ListView。当你点击它时,想要在右侧加载一个Fragment

当我进入这个Activity时,通过Intent传递了一个Category对象。这个对象包含另外一个对象Questions列表(这个列表包含了一个字符串列表)。Questions对象会在ListView上显示出来。 当我点击ListView中的一个项目时,想要在Fragment中显示String列表(以ListView形式)。

为了实现这个功能,我从Activity调用setContentView()方法并传入一个布局。在这个布局中定义了正确的Fragment类。 当我调用这个setContentView()方法时,FragmentonCreateView()方法被调用,但此时getArguments()返回null。

我该如何在调用onCreateView()之前填充它呢? (如果我表达的不够清晰,请告诉我)

谢谢

8个回答

140

Fragment中创建一个静态方法,然后使用getArguments()获取它。

例如:

public class CommentsFragment extends Fragment {
  private static final String DESCRIBABLE_KEY = "describable_key";
  private Describable mDescribable;

  public static CommentsFragment newInstance(Describable describable) {
    CommentsFragment fragment = new CommentsFragment();
    Bundle bundle = new Bundle();
    bundle.putSerializable(DESCRIBABLE_KEY, describable);
    fragment.setArguments(bundle);

    return fragment;
  }

  @Override
  public View onCreateView(LayoutInflater inflater,
      ViewGroup container, Bundle savedInstanceState) {

    mDescribable = (Describable) getArguments().getSerializable(
        DESCRIBABLE_KEY);

    // The rest of your code
}
你之后可以在 Activity 中通过像这样的方式来调用它:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment fragment = CommentsFragment.newInstance(mDescribable);
ft.replace(R.id.comments_fragment, fragment);
ft.commit();

9
如何传递一个不可序列化的对象? - Bagusflyer
2
putParcelable是最佳实践的方式。 - panchicore
9
我很乐意知道为什么不在newInstance中简单地设置 fragment.mDescribable = describable;?这样做是有效的,但我是否遗漏了什么重要信息? - Rahul Thakur
2
@RahulThakur,你在这里忽略了 m 前缀的意义。由于 Java 社区强烈鼓励数据封装的概念,应该注意到私有字段不需要在外部访问。单例方法将其作为参数传递的原因是因为在该上下文中该字段是必需的,从而减少您忘记分配其值的潜在风险。 - mr5
17
最佳答案,但你忘了说Object需要实现Serializable才能正常工作(在这种情况下,是对象Describable)。 - Gabriel Stafoca
显示剩余8条评论

15

在你的活动类中:

public class BasicActivity extends Activity {

private ComplexObject co;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_page);

    co=new ComplexObject();
    getIntent().putExtra("complexObject", co);

    FragmentManager fragmentManager = getFragmentManager();
    Fragment1 f1 = new Fragment1();
    fragmentManager.beginTransaction()
            .replace(R.id.frameLayout, f1).commit();

}
注意:您的对象应实现Serializable接口
然后在您的碎片中:
public class Fragment1 extends Fragment {

ComplexObject co;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    Intent i = getActivity().getIntent();

    co = (ComplexObject) i.getSerializableExtra("complexObject");

    View view = inflater.inflate(R.layout.test_page, container, false);
    TextView textView = (TextView) view.findViewById(R.id.DENEME);
    textView.setText(co.getName());

    return view;
}
}

这对我来说完美地工作了!谢谢@Tugce Saritas - juske

13

您应该在片段内创建一个方法,该方法接受您希望传递到其中的对象类型。在这种情况下,我将其命名为“setObject”(创意不错,是吗? :))该方法随后可以执行您需要的任何操作。

MyFragment fragment;

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);

        if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
            fragment = new MyFragment();
            getSupportFragmentManager().beginTransaction().add(android.R.id.content, detailsFragment)
                    .commit();
        } else {
           fragment = (MyFragment) getSupportFragmentManager().findFragmentById(
                    android.R.id.content);
        }


        fragment.setObject(yourObject); //create a method like this in your class "MyFragment"
}

请注意,我正在使用支持库,而调用getSupportFragmentManager()可能会因您所使用的内容而变为getFragmentManager()


2
在使用此方法时要小心,特别是在一个可能比您的宿主视图更长寿的片段上(保留实例为true)。 - Jannie Theunissen
7
这样做不行。当你的应用程序在后台中停止运行,用户将其切换回前台时,“setObject”可能不会被调用。 - Martin Konecny
5
在这种情况下,onCreate方法将被再次调用(因为活动将被重新创建),因此也会调用setObject。如果不是这种情况,请解释一下您的评论。谢谢。 - fklappan
在视图分页片段中,这种方法不起作用,因为对象在转换过程中没有被保留。 - rafa

7

请参考以下示例。

1. 在Fragment中: 为想要在Fragment中使用的类创建一个引用变量。只需为引用变量创建一个setter方法,在从Activity替换Fragment之前调用该方法即可。

 MyEmployee myEmp;
 public void setEmployee(MyEmployee myEmp)
 {
     this.myEmp = myEmp;
 }

2. 在活动中:

   //we need to pass object myEmp to fragment myFragment

    MyEmployee myEmp = new MyEmployee();

    MyFragment myFragment = new MyFragment();

    myFragment.setEmployee(myEmp);

    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.replace(R.id.main_layout, myFragment);
    ft.commit();

5
传递参数的bundle方式仅限于某些数据类型。但您可以通过以下方式将任何数据传递到片段中:
在片段中创建一个公共方法,如下所示:
public void passData(Context context, List<LexItem> list, int pos) {
    mContext = context;
    mLexItemList = list;
    mIndex = pos;
}

在您的活动中实例化片段后,使用所有所需的数据类型调用passData()函数。
        WebViewFragment myFragment = new WebViewFragment();
        myFragment.passData(getApplicationContext(), mLexItemList, index);
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        ft.add(R.id.my_fragment_container, myFragment);
        ft.addToBackStack(null);
        ft.commit();

注意:我的片段扩展了“android.support.v4.app.Fragment”,因此我必须使用“getSupportFragmentManager()”。当然,如果你的片段类扩展了“Fragment”,那么你就需要使用“getFragmentManager()”。

1
要将对象传递给片段,请执行以下操作:
首先将对象存储在Bundle中,不要忘记在类中加入implements serializable。
            CategoryRowFragment fragment = new CategoryRowFragment();

            // pass arguments to fragment
            Bundle bundle = new Bundle();

            // event list we want to populate
            bundle.putSerializable("eventsList", eventsList);

            // the description of the row
            bundle.putSerializable("categoryRow", categoryRow);

            fragment.setArguments(bundle);

然后在Fragment中检索bundles

       // events that will be populated in this row
        mEventsList = (ArrayList<Event>)getArguments().getSerializable("eventsList");

        // description of events to be populated in this row
        mCategoryRow = (CategoryRow)getArguments().getSerializable("categoryRow");


0
如果数据需要在应用程序生命周期中存活并在多个片段或活动之间共享,则可能考虑使用Model类,其序列化开销较小。
请查看此设计示例

-1

这个方法对我管用:

在 Activity 中:

User user;
public User getUser(){ return this.user;}

在 Fragment 的 onCreateView 方法中:
User user = ((MainActivity)getActivity()).getUser(); 

MainActivity替换为您的Activity名称。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接