I'm starting an Activity through the usual means:
Intent startIntent = new Intent(this, DualPaneActivity.class);
startIntent.putExtras(((SearchPageFragment) currentFragment).getPageState());
startActivity(startIntent);
When this activity loads, it places a Fragment in a frame like so:
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
Fragment currentFragment = fragment;
currentFragment.setArguments(getIntent().getExtras());
transaction.replace(R.id.singlePane, currentFragment);
transaction.commit();
Seems simple, right?
However, you can inside of onCreateView() method access three separate bundles (four, if you include the one included in the Fragment's onCreate(Bundle savedInstanceState)):
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Fill state information
Bundle bundle;
if(savedInstanceState != null) bundle = savedInstanceState; // 1
else if(getArguments() != null) bundle = getArguments(); // 2
else bundle = getActivity().getIntent().getExtras(); // 3
setPageState(bundle);
}
In the above instance, I've worked out from trial and error that the bundle I want is the second one, the one retrieved from getArguments().
From my understanding the third one from getActivity().getIntent().getExtras(); is actually calling the Bundle from the intent used to start containing activity. I also know from experimentation that savedInstanceState seems to always be null. But where is it coming from and why is it null?
The documentation says this:
savedInstanceState If non-null, this fragment is being re-constructed
from a previous saved state as given here.
That doesn't help me - It's bugging me more than stopping me from moving on. Can someone help me out with this annoyance?
To the best of my knowledge, onCreateView and onCreate() are both passed the bundle from onSaveInstanceState().
So if you override onSaveInstanceState() and put data in the bundle, you should be able to retrieve it in onCreateView(). That is why the documentation says that the bundle will be non-null when the fragment is re-constructed from a previous saved state.
Related
I create the bundle in my Activity with
ListFragment fragment = new ListFragment();
Bundle bundle = new Bundle();
bundle.putInt("i", 0);
Log.i("Bundle", String.valueOf(bundle.getInt("i")));
fragment.setArguments(bundle);
And I get the arguments in my Fragment with
Bundle bundle = this.getArguments();
if (bundle != null) {
myInt = bundle.getInt("i", -1);
}
But it says that my bundle is null. Any idea why?
Are you sure that the fragment you want to read the arguments was created from the provided code block #1? Your code is correct, there is nothing wrong so it must work. (as long as the arguments are accessed after onCreate, which they are)
I had the same issue, I initially had my bundle variable declared outside the onCreateView function. Once I moved it inside, it worked for me
Playing around with Fragments, I came to wonder about the right way to populate my fragments.
As the doc says, I use the newInstance() pattern to add arguments to my fragments :
public static ItemFragment newInstance(ItemRealm item, AnnaleModel model) {
ItemFragment fragment = new ItemFragment();
Bundle args = new Bundle();
args.putString(MyPagerAdapter.KEY_ITEM, item.getId());
args.putParcelable(MyPagerAdapter.KEY_MODEL, model);
fragment.setArguments(args);
return fragment;
}
But then, there is several behaviours I can see happening on the net.
The most seen it to put getArguments() in the onCreateView() method and put the results in fields :
protected String itemId;
protected Model mModel ;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Bundle args = getArguments();
if (args == null || (!args.containsKey(MyPagerAdapter.KEY_ITEM) || !args.containsKey(MyPagerAdapter.KEY_MODEL))) {
Log.e("TAG", "incorrect Bundle");
return null;
}
itemId = args.getString(MyPagerAdapter.KEY_ITEM);
mModel = args.getParcelable(MyPagerAdapter.KEY_MODEL);
}
I can see on some other places to put the same exact thing in the Fragment.onCreate() method instead of onCreateView().
And the last behaviour is to call getArguments() in the getter.
private Model getModel(){
if (getArguments() != null) {
return getArguments().getParcelable(AnnalePagerAdapter.KEY_MODEL);
}
Log.e("Dan", "ItemFragment :: getModel (279): model==null !!");
return null;
}//I can also think about some lazyloading is needed
The questions are then :
Is there now a consensus on which pattern to use (these 3 or even another) ?
Is there some contexts I should rather use one than another ?
Don't use a getter. That just complicates things imo. Why include fragment logic in the the Model class, right?
As for onCreateView() vs onCreate(), I call getArguments() in onCreate() because this method is called before the view is created. So, if you have any calculations or other stuff then you can do it here. Save it in global vars and set them in onCreateView. But instead of doing that, you can just do it in onCreateView, right? So what's the difference then? It helps to keep the logic separated. Initialize/update the view in onCreateView and do pre-calculations stuff in onCreate
Example from google's samples
This question already has answers here:
Send data from activity to fragment in Android
(22 answers)
Closed 5 years ago.
I have passed some key and value data from one activity to another activity fragment so I have not get key and value to the last point in the fragment.
I have passing data using bundle.
In your activity create bundle to set to the fragment
Yourfragment fragment = new Yourfragment();
Bundle args = new Bundle();
args.putString(ARG_DATA, data);
fragment.setArguments(args);
Then load the fragment getSupportFragmentManager().beginTransaction().replace(R.id.your_container,fragment).commit();
Then in your fragment oncreate get the data like this
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mData = getArguments().getString(ARG_DATA);
}
}
From activity to activity you can pass data by using Intent and when you get data in second activity in which you are creating fragments on creating fragment pass that data to fragment by making constructor in fragment or by using bundle. For further assistance and if you dont know how to do this do let me know.
Pass data from activity to activity:
Intent intent = new Intent(this, Second.class);
intent.putExtra("data", sessionId);
startActivity(intent);
get data in Second activity:
String s = getIntent().getStringExtra("data");
Pass data from activity to fragment:
Bundle bundle = new Bundle();
bundle.putString("data", "From Activity");
// set Fragmentclass Arguments
FragmentOne fragment = new FragmentOne ();
fragment.setArguments(bundle);
get data from activity to fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String strtext = getArguments().getString("data");
return inflater.inflate(R.layout.fragment, container, false);
}
Happy coding!!
You can pass data between Activity and Fragments and Fragment to fragment using below:
https://developer.android.com/training/basics/fragments/communicating.html
But to pass it between activity, you may use bundle data, (very few variables) or use Application Class to store it in memory, make sure you do not bloat up your memory.
New Android architecture components also do provide good options, it all depends upon your use:
https://developer.android.com/topic/libraries/architecture/index.html
I have seen Bundles restored in several of the Android callback methods, but in many cases there is manual creation and setting of Bundles as on the developers website, in this case from an external message on Fragment creation:
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;
}
In this other question, for example, bundle data is restored in the onCreateView() method.
public class Frag2 extends Fragment {
public View onCreateView(LayoutInflater inflater,
ViewGroup containerObject,
Bundle savedInstanceState){
//here is your arguments
Bundle bundle=getArguments();
//here is your list array
String[] myStrings=bundle.getStringArray("elist");
}
}
I am a bit confused about the Bundle data supplied with each callback method VS "other bundles":
Bundle bundle=getArguments();
and the correct way and place to retrieve these different types of bundled data.
Thanks in advance!
The two ways described above are exactly the correct way to
initialize a new instance of the Fragment and pass the initial parameters.
retrieve the initial parameters in the Fragment.
In other words, you're on the right track! It should work, and you should be pleased with yourself :)
EDIT:
The Bundle can be retrieved in either onCreateView() or
onCreate(). I'd prefer onCreate(), as it represents the creation
of the Fragment instance and is the right place for initialization.
There is always one and only one Bundle instance retrieved by the call to getArguments(), and this Bundle instance contains all of your ints, Strings, whatever.
Currently I have been diving into the Fragment world: http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity
I understand that by creating a listener in the fragment and then implementing it in the Activity which hosts the fragment is a great way to communicate from the fragment to the Activity, but how do I get communicate back from the activity to the fragment? Another listener? Perhaps I don't fully understand what the listener is doing. Any help with this topic explaining how to communicate from activity to fragment would be much appreciated!
P.S. I am currently converting an activity (B) that I made into a fragment. I use to do some intent.putExtra("value") from Activity A before starting Activity B so this is what I am looking to replace... Probably doesn't help you at all but I thought I'd try and put it into perspective what I am doing.
I may have found the solution, lol. I'll do some checks to make sure this works and confirm it later.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Bundle b = getActivity().getIntent().getExtras();
wid = b.getString("wid");
rid = b.getString("rid");
View view = inflater.inflate(R.layout.categoryfragment, container, false);
return view;
}
Just like you do when you create an Activity, you can pass a Bundle to a Fragment.
There's an example on how to do that on the Fragment class reference.
/**
* 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;
}
Use getArguments() to get the Bundle back.