86

I have an Activity which uses a Fragment. I simply want to pass an object from this Activity to the Fragment.

How could I do it? All the tutorials I've seen so far where retrieving data from resources.

EDIT :

Let's be a bit more precise:

My Activity has a ListView on the left part. When you click on it, the idea is to load a Fragment on the right part.

When I enter this Activity, an Object Category is given through the Intent. This Object contains a List of other Objects Questions (which contains a List of String). These Questions objects are displayed on the ListView. When I click on one item from the ListView, I want to display the List of String into the Fragment (into a ListView).

To do that, I call the setContentView() from my Activity with a layout. In this layout is defined the Fragment with the correct class to call. When I call this setContentView(), the onCreateView() of my Fragment is called but at this time, the getArguments() returns null.

How could I manage to have it filled before the call of onCreateView() ? (tell me if I'm not clear enough)

Thanks

Catarina Ferreira
  • 1,824
  • 5
  • 17
  • 26
Nico
  • 6,269
  • 9
  • 45
  • 85

8 Answers8

140

Create a static method in the Fragment and then get it using getArguments().

Example:

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
}

You can afterwards call it from the Activity doing something like:

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment fragment = CommentsFragment.newInstance(mDescribable);
ft.replace(R.id.comments_fragment, fragment);
ft.commit();
Macarse
  • 91,829
  • 44
  • 175
  • 230
  • Hello Macarse, when your method newInstance is called ? – Nico Mar 29 '12 at 20:22
  • Are you sure you meant `Describable` instead of `Serializable`? – Jens Kohl Jan 08 '13 at 16:43
  • yup it's `Describable`; he's casting the serialised data back to its class – yeahman Jun 23 '13 at 15:05
  • 9
    What is I want to pass some object which is not Serializable? – Bagusflyer Mar 23 '14 at 02:55
  • 2
    putParcelable is the best practice way – panchicore Jul 19 '14 at 17:10
  • 9
    I would love to know why not simply set `fragment.mDescribable = describable;` in newInstance? It works, but is there something that I am missing here? – Rahul Thakur Mar 10 '15 at 22:18
  • 2
    @RahulThakur You are missing the point of the `m` prefix here. As the Java community strongly encourages the concept of data encapsulation, it should be noted that private fields need not be accessible outside. The reason why, it is passed as a parameter from the singleton method is because that field is mandatory in that context, and thus reducing the potential risk that you will forgot to assign its value. – mr5 Feb 03 '16 at 07:06
  • 17
    Best answer, but you forget to say that `Object` need to implements `Serializable` to work (in the case, the object `Describable`). – Gabriel Stafoca Aug 30 '16 at 00:12
  • @GabrielStafoca yeah, I don't know about `Describable`, but many other objects will require to put them in class that implements `Serializable` and then we can send this class using `bundle.putSerializable`. And author of this answer really didn't mention about it. So it's not a good answer... – user25 Sep 03 '16 at 09:06
  • 1
    @RahulThakur Because you can't set an instance variable (mDescribable) from a static context. – felippe Mar 16 '18 at 00:08
  • It would seem `Parcelable` gives as much as a 10x speed boost -- http://www.developerphil.com/parcelable-vs-serializable/ – Bondolin Mar 24 '18 at 16:54
  • What if I need to pass some complex object to Fragment from Activity after some period of time, when Fragment is already visible? Can I just add public method like this: public void setCustomDataToFragment(MyCustomObject obj)? – yozhik Apr 06 '18 at 12:56
  • @RahulThakur Android system calls the no argument constructor when re-creating the fragment for eg. on activity configuration changed. Ideally fragment parameters should be passed through arguments. – rd7773 Sep 28 '20 at 07:16
15

In your activity class:

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();

}

Note: Your object should implement Serializable interface

Then in your fragment :

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;
}
}
Luís Cruz
  • 14,780
  • 16
  • 68
  • 100
Tugce Saritas
  • 169
  • 1
  • 5
13

You should create a method within your fragment that accepts the type of object you wish to pass into it. In this case i named it "setObject" (creative huh? :) ) That method can then perform whatever action you need with that object.

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"
}

Note that i'm using the support library and calls to getSupportFragmentManager() might be just getFragmentManager() for you depending on what you're working with

dymmeh
  • 22,247
  • 5
  • 53
  • 60
  • 2
    Just be careful when using this method on a fragment that can outlive your hosting view (retainInstance true). – Jannie Theunissen Aug 05 '13 at 16:48
  • 7
    This won't work. When your app dies in the background, and the user brings it back to the foreground, `setObject` won't necessarily be called. – Martin Konecny Sep 07 '14 at 20:12
  • 5
    @MartinKonecny in that case the onCreate method will be called again (because the activity will be recreated) and therefore also setObject would be called. If it is not the case, please explain your comment. Thank you. – fklappan Oct 04 '16 at 08:55
  • This doesn't work in case of view pager fragments. since the object is not retained on the transition. – rafa Jun 13 '17 at 13:22
7

Get reference from the following example.

1. In fragment: Create a reference variable for the class whose object you want in the fragment. Simply create a setter method for the reference variable and call the setter before replacing fragment from the activity.

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

2. In activity:

   //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();
Shivam Agarwal
  • 133
  • 1
  • 6
5

Passing arguments by bundle is restricted to some data types. But you can transfer any data to your fragment this way:

In your fragment create a public method like this

public void passData(Context context, List<LexItem> list, int pos) {
    mContext = context;
    mLexItemList = list;
    mIndex = pos;
}

and in your activity call passData() with all your needed data types after instantiating the fragment

        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();

Remark: My fragment extends "android.support.v4.app.Fragment", therefore I have to use "getSupportFragmentManager()". Of course, this principle will work also with a fragment class extending "Fragment", but then you have to use "getFragmentManager()".

thpitsch
  • 2,016
  • 2
  • 21
  • 27
1

To pass an object to a fragment, do the following:

First store the objects in Bundle, don't forget to put implements serializable in class.

            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);

Then retrieve bundles in Fragment

       // 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");
dave o grady
  • 788
  • 8
  • 12
0

If the data should survive throughout the application lifecycle and shared among multiple fragments or activities, a Model class might come into consideration, which has got less serialization overhead.

Check this design example

Xerusial
  • 525
  • 1
  • 5
  • 17
-1

This one worked for me:

In Activity:

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

In Fragment's onCreateView method:

User user = ((MainActivity)getActivity()).getUser(); 

Replace the MainActivity with your Activity Name.

Pranjal Choladhara
  • 845
  • 2
  • 14
  • 35