Where/How to getIntent().getExtras() in an Android Fragment?

147,856

Solution 1

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)

}

Solution 2

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.

Share:
147,856

Related videos on Youtube

TheLettuceMaster
Author by

TheLettuceMaster

Android (Java) Developer for fun, and Professional Full Stack Developer using python, ruby, JavaScript, SQL and php.

Updated on September 15, 2020

Comments

  • TheLettuceMaster
    TheLettuceMaster over 3 years

    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
      TheLettuceMaster almost 9 years
      It might be a duplicate but people seem to like this question more. I'm just saying.
    • andreikashin
      andreikashin about 5 years
      this question has NOT been asked before
  • TheLettuceMaster
    TheLettuceMaster almost 12 years
    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?
  • MH.
    MH. almost 12 years
    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.
  • TheLettuceMaster
    TheLettuceMaster almost 12 years
    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)
  • MH.
    MH. almost 12 years
    Similar to shown in the example: String item = getArguments().getString("name");. As usual, a default value can optionally added as second parameter.
  • TheLettuceMaster
    TheLettuceMaster almost 12 years
    Ah ok, exactly what you have there in the getter method - getShownIndex() -- thanks alot! I went ahead and just marked this correct...
  • MH.
    MH. almost 12 years
    Another example (with a CharSequence) 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(...).
  • TheLettuceMaster
    TheLettuceMaster almost 12 years
    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)
  • MH.
    MH. almost 12 years
    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).
  • Royston Pinto
    Royston Pinto about 11 years
    This saves a lot of code writing! good one :)
  • colabug
    colabug almost 11 years
    Is there a way to do this when you have your fragments specified in XML instead of using the transaction manger?
  • MH.
    MH. almost 11 years
    @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).
  • colabug
    colabug almost 11 years
    @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
    colabug almost 11 years
    @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.
  • MH.
    MH. almost 11 years
    @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.
  • zeeshan
    zeeshan over 10 years
    A simple and elegant way to retrieve intent data.
  • Blundell
    Blundell over 10 years
    @zeeshan Hardly simple or elegant. More like coupling and complexity
  • TheIT
    TheIT over 10 years
    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.
  • Jim G.
    Jim G. over 10 years
    Do you know why Google recommends that you use the newInstance method instead of passing the arguments directly through the constructor?
  • MH.
    MH. over 10 years
    @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 helpful to read.
  • Jim G.
    Jim G. over 10 years
    Thanks! I didn't know that.
  • LK Yeung
    LK Yeung about 9 years
    Save time when moving code from activity to fragment
  • Amitabha Biswas
    Amitabha Biswas about 9 years
    Its working for me..but it crashes sometime..when get NULL value..NULL value checking not woring.
  • ernazm
    ernazm over 8 years
    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
  • Behzad Bahmanyar
    Behzad Bahmanyar over 8 years
    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.
  • user3833732
    user3833732 over 6 years
    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 :-)
  • Michał Jabłoński
    Michał Jabłoński over 4 years
    I agree with @TheIT