Where/How to getIntent().getExtras() in an Android Fragment?
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.
Related videos on Youtube
TheLettuceMaster
Android (Java) Developer for fun, and Professional Full Stack Developer using python, ruby, JavaScript, SQL and php.
Updated on September 15, 2020Comments
-
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 almost 9 yearsIt might be a duplicate but people seem to like this question more. I'm just saying.
-
andreikashin about 5 yearsthis question has NOT been asked before
-
-
TheLettuceMaster almost 12 yearsHey 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. almost 12 yearsJust add as many parameters to
newInstance(...)
as you need to pass on extras, and put each one into the argumentsBundle
. Personally, I normally retrieve all the arguments within one of the fragment'sonCreate...()
methods and assign them to variables. That way you should be able to use them anywhere within the implementation. -
TheLettuceMaster almost 12 yearsOn 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. almost 12 yearsSimilar to shown in the example:
String item = getArguments().getString("name");
. As usual, a default value can optionally added as second parameter. -
TheLettuceMaster almost 12 yearsAh ok, exactly what you have there in the getter method - getShownIndex() -- thanks alot! I went ahead and just marked this correct...
-
MH. almost 12 yearsAnother example (with a
CharSequence
) can be found in the documentation of a fragment'sinflate(...)
method, in case you need more pointers. The samenewInstance(...)
approach is used in there, and the value is retrieved inonCreate(...)
. -
TheLettuceMaster almost 12 yearsHey 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. almost 12 yearsIf 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 about 11 yearsThis saves a lot of code writing! good one :)
-
colabug almost 11 yearsIs there a way to do this when you have your fragments specified in XML instead of using the transaction manger?
-
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 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 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. 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 over 10 yearsA simple and elegant way to retrieve intent data.
-
Blundell over 10 years@zeeshan Hardly simple or elegant. More like coupling and complexity
-
TheIT over 10 yearsThis 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. over 10 yearsDo you know why Google recommends that you use the
newInstance
method instead of passing the arguments directly through the constructor? -
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. over 10 yearsThanks! I didn't know that.
-
LK Yeung about 9 yearsSave time when moving code from activity to fragment
-
Amitabha Biswas about 9 yearsIts working for me..but it crashes sometime..when get NULL value..NULL value checking not woring.
-
ernazm over 8 yearsThis 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 over 8 yearsNot 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 over 6 yearsThis 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 over 4 yearsI agree with @TheIT