how to make a constructor for a fragment - android

I was just wondering how I could send parameters or arguments to a Fragment before it is created. Because I want to pass an array of strings to the fragment so that it could put all of them in the layout when it is created. For example I am making a Leaderboard fragment, and my activitiy would pass in all of the scores etc. that the fragment would use to display. I understand that I can use the Bundle and the .setArgs but will that work for my case?
Thank you
** EDIT **
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View singleplayerView = inflater.inflate(R.layout.singleplayer_tab, container, false);
String[] scores = (String[]) getArguments().get("scores");
TextView tview = (TextView) singleplayerView.findViewById(R.id.player_name0);
tview.setText(scores[0]);
setupRank(singleplayerView);
return singleplayerView;
}
public static SingleplayerTab newInstance(String[] scores) {
SingleplayerTab spt = new SingleplayerTab();
Bundle args = new Bundle();
args.putStringArray("scores", scores);
spt.setArguments(args);
return spt;
}
CODE THAT CALLS IT
String[] scores = {"hello"};
Fragment singlePlayerFragment = SingleplayerTab.newInstance(scores);

I understand that I can use the Bundle and the .setArgs but will that work for my case?
A Bundle can hold an String[] or an ArrayList<String>.
Moreover, this is the way you should do it, rather than a custom constructor. Android automatically recreates your fragments on a configuration change (e.g., screen rotation), and it will use your public zero-argument constructor for that. Hence, unless you use the arguments Bundle, or something else, you will lose your string array on a configuration change.
The recommended approach for this is to use a factory method, such as this one from an EditorFragment:
static EditorFragment newInstance(int position) {
EditorFragment frag=new EditorFragment();
Bundle args=new Bundle();
args.putInt(KEY_POSITION, position);
frag.setArguments(args);
return(frag);
}
In this case, I want to pass int position into the fragment. I isolate packaging this into the Bundle into the factory method (newInstance()). When I need to create an instance of this fragment, I call EditorFragment.newInstance() instead of new EditorFragment, so I can supply the position. My fragment can get the position by reading the KEY_POSITION value out of the getArguments() Bundle. I use this approach in (among other places) this sample project, showing loading 10 of these editors into a ViewPager.

Related

Fragment getArgument() right location

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

What's the most efficient way to deal with 20+ different static layouts?

Right now I'm making an app that requires me to have about 20 or more different pages/layouts, one loaded at a time, but little/no intercommunication between them. They would be very static. Right now I had the idea to have one activity, one fragment that would inflate a different layout in the onCreateView, and the fragment would be reloaded everytime the user selected another page. However I just realized that wouldn't work at all because I can't put the return statement of onCreateView in an if statement, and no workaround work.
So now I don't know the most efficient way to do this. There's no way having 20+ layouts and 20+ classes, one for each page is ideal. It seems very redundant.
You can use the Fragment's bundle to communicate to it which layout to use.
In the Fragment class, create a static method to create the Fragment instance and set it's bundle, for example:
public static MyFragment newInstance(int layoutId) {
MyFragment f = new MyFragment();
Bundle args = new Bundle();
args.putInt("layoutId", layoutId); // e.g. layoutId = R.layout.layout_fragment_01
f.setArguments(args);
return f;
}
and then in the fragment's onCreateView, get the layout id from the bundle:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(getArguments().getInt("layoutId", 0), container, false);
}
then, in your Activity, you'd do something like the following:
MyFragment fragment = MyFragment.newInstance(R.layout.fragment_layout_01);
getFragmentManager().beginTransaction().add(android.R.id.content, fragment).commit();

The correct way and place to restore bundle information on a fragment?

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.

Which bundle should be used to pass an object

I would like to pass an object from an activity to a fragment. I know how to pass the data but do not know which type of bundle i should use?
UPdate
In other words, I have an object of type mqttAndroidClient and that object i want to pass from my activity to a fragment through a bundle. Which bundle type I should use?
For relatively simple object data types, you shouldn't need a bundle at all. When you override onCreate() in the fragment that uses the argument, simply add a line of code that fetches the data from the intent.
For example, if you're passing an integer, the line would be:
intvar = (int)getActivity().getIntent().getInt(SOME_IDENTIFIER);
where SOME_IDENTIFIER is a constant that's common to both the activity and the fragment. (It would look something like "com.yourpackage.yourapp.some_identifier."
you should use something like this :
make your custom class that contains your desired data to be passed and extend from Serializable or Parcelable and put your object as extra to your Bundle object and set Bundle as an argument to your Fragment.
in your Activity
...
Fragment fragment = new YourFragment();
Bundle bundle = new Bundle();
bundle.putString("data", "yourData");
fragment.setArguments(bundle);
...
in your Fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String data = getArguments().getString("data");
...
}

Android - Communicating from Activity to fragment that it hosts

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.

Categories

Resources