108

With Activities, I used to do this:

In Activity 1:

Intent i = new Intent(getApplicationContext(), MyFragmentActivity.class);
                i.putExtra("name", items.get(arg2));
                i.putExtra("category", Category);
                startActivity(i);

In Activity 2:

Item = getIntent().getExtras().getString("name");

How do you do this using Fragments? I am using the compatibility library v4 also.

Does it go in the FragmentActivity? Or the actual Fragment? And Which Method does it go in? onCreate? onCreateView? another?

And can I see example code please?

EDIT: It is worth noting I am trying to keep Activity 1 as an Activity (or actually ListActivity where I am passing the intent of the listitem when clicked) and then pass to a set of tabbed-fragments (through a Fragment Activity) and I need either tab to be able to get the extras. (I hope this is possible?)

TheLettuceMaster
  • 15,594
  • 48
  • 153
  • 259

2 Answers2

176

you can still use

String Item = getIntent().getExtras().getString("name");

in the fragment, you just need call getActivity() first:

String Item = getActivity().getIntent().getExtras().getString("name");

This saves you having to write some code.

kenju
  • 5,866
  • 1
  • 41
  • 41
meeeee
  • 2,929
  • 3
  • 22
  • 25
  • 8
    @zeeshan Hardly simple or elegant. More like coupling and complexity – Blundell Dec 16 '13 at 13:28
  • 51
    This may be a simple solution, but it is not a good practice. The reason for this is because it creates a strong dependence between the Fragment and the Activity. The main downsides to this are 1)The Fragment becomes non-reusable (at least without introducing additional constraints to any Activity that uses it). 2)It creates a n non-obvious soft requirement on the use of the Fragment (it's not clear that using the fragment requires that any intent passed to it's Activity have specific Intent entries). At least be aware of the correct way of passing around data and make an informed decision. – TheIT Jan 03 '14 at 03:33
  • Save time when moving code from activity to fragment – LK Yeung Mar 23 '15 at 11:05
  • Its working for me..but it crashes sometime..when get NULL value..NULL value checking not woring. – Amitabha Biswas Mar 29 '15 at 08:13
  • 8
    This is wrong approach that doesn't work in some cases. The lifecycle of fragment isn't strongly tied to lifecycle of activity, so you can get null invoking getActivity(). It's safe only in fragment's onCreate and some other callbacks – ernazm Nov 18 '15 at 14:14
  • Not a good pattern. because it's depending the activity to get the data from intent so later you cannot get data from inside activity. so decreasing fragment reusablity. – Behzad Bahmanyar Jan 18 '16 at 04:58
  • This is a great answer! But pls understand the caution mentioned by @ernazm. If both their life cycles are tied to each other its perfect, else you might want to end both at the same time by calling getActivity().finish(); then this worked safely for me :-) – user3833732 Dec 02 '17 at 21:08
111

What I tend to do, and I believe this is what Google intended for developers to do too, is to still get the extras from an Intent in an Activity and then pass any extra data to fragments by instantiating them with arguments.

There's actually an example on the Android dev blog that illustrates this concept, and you'll see this in several of the API demos too. Although this specific example is given for API 3.0+ fragments, the same flow applies when using FragmentActivity and Fragment from the support library.

You first retrieve the intent extras as usual in your activity and pass them on as arguments to the fragment:

public static class DetailsActivity extends FragmentActivity {

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

        // (omitted some other stuff)

        if (savedInstanceState == null) {
            // During initial setup, plug in the details fragment.
            DetailsFragment details = new DetailsFragment();
            details.setArguments(getIntent().getExtras());
            getSupportFragmentManager().beginTransaction().add(
                    android.R.id.content, details).commit();
        }
    }
}

In stead of directly invoking the constructor, it's probably easier to use a static method that plugs the arguments into the fragment for you. Such a method is often called newInstance in the examples given by Google. There actually is a newInstance method in DetailsFragment, so I'm unsure why it isn't used in the snippet above...

Anyways, all extras provided as argument upon creating the fragment, will be available by calling getArguments(). Since this returns a Bundle, its usage is similar to that of the extras in an Activity.

public static class DetailsFragment extends Fragment {
    /**
     * Create a new instance of DetailsFragment, initialized to
     * show the text at 'index'.
     */
    public static DetailsFragment newInstance(int index) {
        DetailsFragment f = new DetailsFragment();

        // Supply index input as an argument.
        Bundle args = new Bundle();
        args.putInt("index", index);
        f.setArguments(args);

        return f;
    }

    public int getShownIndex() {
        return getArguments().getInt("index", 0);
    }

    // (other stuff omitted)

}
Jim G.
  • 15,141
  • 22
  • 103
  • 166
MH.
  • 45,303
  • 10
  • 103
  • 116
  • Hey thanks, I will mark this as correct after I get to try this out but it looks good to me! In the meantime, if I want to take the value of the intent and set that text on a textView -- based on your answer, would it be like this? 'tv.setText(getShownIndex())' ? And I am actually grabbing TWO different extras --- in my case "names", and "categories" -- how does that change the code above? – TheLettuceMaster Jul 09 '12 at 14:23
  • Just add as many parameters to `newInstance(...)` as you need to pass on extras, and put each one into the arguments `Bundle`. Personally, I normally retrieve all the arguments within one of the fragment's `onCreate...()` methods and assign them to variables. That way you should be able to use them anywhere within the implementation. – MH. Jul 09 '12 at 19:20
  • On retrieving in the onCreate, what is the syntax? Normally I used 'Item = getIntent().getExtras().getString("name");' How does it change now? (I think this answers the last remaining question) – TheLettuceMaster Jul 09 '12 at 21:49
  • Similar to shown in the example: `String item = getArguments().getString("name");`. As usual, a default value can optionally added as second parameter. – MH. Jul 09 '12 at 21:53
  • Ah ok, exactly what you have there in the getter method - getShownIndex() -- thanks alot! I went ahead and just marked this correct... – TheLettuceMaster Jul 09 '12 at 21:56
  • [Another example (with a `CharSequence`)](http://developer.android.com/reference/android/app/Fragment.html#onInflate%28android.app.Activity,%20android.util.AttributeSet,%20android.os.Bundle%29) can be found in the documentation of a fragment's `inflate(...)` method, in case you need more pointers. The same `newInstance(...)` approach is used in there, and the value is retrieved in `onCreate(...)`. – MH. Jul 09 '12 at 21:58
  • Hey thanks, I needed CharSequence over an int example that helped. QUICK question: I want to retrieve "String item" and then set it in a TextView. That should happen in the Activity? and if so, what method? onCreate? I was trying to do that in the Fragment but was told that was an unusual way of handling it. (By letting a Fragment manipulate an Activity like that) – TheLettuceMaster Jul 10 '12 at 18:02
  • 1
    If the `TextView` is part to the fragment's UI, then the activity has little to do with that. The whole reason for passing on the intent extras as arguments to the fragment is so that you can use those inside the latter, right? I would recommend going over some of the documentation online and the API samples (which can be downloaded through the Android SDK Manager). – MH. Jul 10 '12 at 19:13
  • 2
    Is there a way to do this when you have your fragments specified in XML instead of using the transaction manger? – colabug Jun 13 '13 at 19:03
  • @colabug: No, as far as I'm aware that's not possible. And that makes sense, if you think about it: declaring fragments statically (in your layouts) implies that they do not need any extra information (arguments) in order to work correctly. If they do, they really should be created at runtime, passing in the extra information (potentially using above approach). – MH. Jun 13 '13 at 19:11
  • 1
    @MH. Disagree that it doesn't make sense to have data update when you have your fragments specified in XML. In my case, it's a recipe detail screen and I already have all the information I need from a set of search results and want to open a detail screen. It will look different for each one that is instantiated, but will have all the same view elements. Defining in XML gives lots of advantages over instantiating in code, especially styles, dimensions, etc. – colabug Jun 13 '13 at 19:45
  • @MH. - I got it working using the below suggestion to use getActivity().getIntent().getExtras().getString("name"); The hardest part is updating the Robolectric tests, but I'm nearly done with that. – colabug Jun 13 '13 at 19:47
  • 1
    @colabug: So your argument would be the recipe data, or at least some sort of identifier unique to the recipe, which is only known at runtime. Hence, I'd opt for dynamically instantiating the fragment. However, a simple alternative would be to call a public method on your fragment directly with the `Intent` data retrieved from the activity, optionally using interfaces if your app is more complex and deals with different fragments in a single container. – MH. Jun 13 '13 at 21:30
  • Do you know why Google recommends that you use the `newInstance` method instead of passing the arguments directly through the constructor? – Jim G. Feb 16 '14 at 14:15
  • 2
    @JimG. Yes, because the platform relies on a non-parameterized constructor to dynamically (re)create `Fragment` instances. There are several related Q&A's here on SO, of which you may find [this one](http://stackoverflow.com/questions/14654766/creating-a-fragment-constructor-vs-newinstance) helpful to read. – MH. Feb 16 '14 at 23:29