Can I use setters over a bundle when creating a new fragment - android

When I first started android development, it was drilled into my head that creating a fragment should always be accomplished through a static method you create that uses the fragments default constructor, assigns arguments through a bundle, sets the bundle on the fragment and then returns it. For example:
public static MyFragment newInstance() {
MyFragment frag = new MyFragment();
Bundle args = new Bundle();
args.putInt("lifesAnswer", 42);
frag.setArguments(args);
return frag;
}
To my vague understanding, the reason we do this is because android will now implicitly handle restoring the fragment and its arguments without any additional work should that outcome happen and restoring is necessary.
Now what if I used the fragments interface in here to set an arbitrary value that could be passed into newInstance() as a parameter. For example:
public static MyFragment newInstance(int someValue) {
MyFragment frag = new MyFragment();
frag.setInstanceValue(someValue); // using a public setter
return frag;
}
for sake of clarity, setInstanceValue() is just your standard setter like:
public void setInstanceValue(int value) {
this.value = value;
}
Is this approach perfectly legal and safe to do. For context in practice here, I have a fragment that will be reused multiple times in a viewpager and all that is different about it is some text and the containers background image. I could just pass the resolved integer values and set them in the bundle for example passing R.String.my_string then setting that in the bundle and using it later but it got me thinking. Is it acceptable to implement the second approach or should I always use the first approach.

You can do something like that:
class YourFragment extends Fragment {
String valueOne;
String valueTwo;
public static YourFragment create(String valueOne, String valueTwo) {
YourFragment fragment = new YourFragment();
fragment.valueOne = valueOne;
fragment.valueTwo = valueTwo;
return fragment;
}
}
There is no need of using setters here.
Or use FragmentArgs https://github.com/sockeqwe/fragmentargs library.

Related

Two constructors for a Fragment

Is it possible to have two different constructors for the same Fragment ?
Here's my case : I have Fragment_A and Fragment_B which are almost identically, except one gets an Integer and the other a String.
Can I have something like this :
public static VideoListFragment newInstanceA(String filterString) {
VideoListFragment myFragment = new VideoListFragment();
Bundle args = new Bundle();
args.putString(FILTER, filterString);
myFragment.setArguments(args);
return myFragment;
}
public static VideoListFragment newInstanceB(String subjectId) {
VideoListFragment myFragment = new VideoListFragment();
Bundle args = new Bundle();
args.putString(POSITION, subjectId);
myFragment.setArguments(args);
return myFragment;
}
If this is possible then how am I going to get in onCreate() the argument ? I have somehow to check if getArguments()` contains FILTER String or POSITION Integer.
You cannot use an exact same method signature to distinguish between different input behaviors. However, you can extend input parameters to make it more versatile. Something like this would help:
public class VideoListFragment extends Fragment {
public static VideoListFragment newInstance(String type, String val) {
VideoListFragment myFragment = new VideoListFragment();
Bundle args = new Bundle();
args.putString(type, val);
myFragment.setArguments(args);
return myFragment;
}
}
and later use it as below:
VideoListFragment frag1 = VideoListFragment.newInstance(FILTER, "value"); //for Filter
VideoListFragment frag2 = VideoListFragment.newInstance(POSITION, "value");//for Position
Android docs discourages the use of constructors while working with fragments; you should use bundle instead.

Passing individual variables vs passing bundle to newInstance

For passing arguments to fragments, I see the best practice is to use a newInstance() method as such:
public static MyFragment newInstance(int myInt) {
MyFragment myFragment = new MyFragment();
Bundle args = new Bundle();
args.putInt("myInt", myInt);
myFragment.setArguments(args);
return myFragment;
}
and this would be instantiated as such:
int myInt = 123;
MyFragment myFragment = MyFragment.newInstance(myInt);
If I need to pass more variables then I would have to append whatever I'm adding to the newInstance() method. Example, if I'm also passing a string then my newInstance() method would look something like:
public static MyFragment newInstance(int myInt, String myStr) {
// code to put the int AND the string into the bundle
}
Now my question is: what's the difference between the above and below method, which passes the bundle?
public static MyFragment newInstance(Bundle args) {
MyFragment myFragment = new MyFragment();
myFragment.setArguments(args);
return myFragment;
}
instantiated by:
int myInt = 123;
Bundle args = new Bundle();
args.putInt("myInt", myInt);
MyFragment myFragment = MyFragment.newInstance(args);
I have been using the latter method so I can keep the parameter for newInstance() short. I have never seen an example using the latter method and I'm wondering if there is something wrong with it.
A bundle can hold multiple values.
Your first code can only send an integer value to the fragment, using a bundle you can send all you need in a single call.
Thats the main difference.
Hope this helps.

It is Possible to Pass a variable to a Previous Fragment from another Fragment?

Im trying to pass a variable back to a previous Fragment, similar to startActivityForResult but with Fragments, Is this possible?
The code I am using To call a Fragment is this:
FragmentFullScreen fragment = new FragmentFullScreen();
Bundle args = new Bundle();
args.putParcelable(ARG_VIDEO_SELECTED, mVideoSelected);
fragment.setArguments(args);
getFragmentManager().beginTransaction()
.replace(R.id.container, FragmentFullScreen.newInstance(mVideoSelected))
.addToBackStack("FragmentDetails")
.commit();
And then I using popBackStack to go to the previous Fragment:
getFragmentManager().popBackStack();
And there is when I want to update a Variable from the Previous Fragment.
You may implement Observable object in your 1st fragment and create Observer, which may be shared through Application class or Activity.
Then in your 2nd fragment you get this Observer from Application and update data.
If you 1st fragment still exists your variable will be passed there.
http://developer.android.com/reference/java/util/Observer.html
http://developer.android.com/reference/java/util/Observable.html
Communication between fragments should be done via the activity. And to achieve this communication between fragment and activity, this is the best way http://developer.android.com/guide/topics/fundamentals/fragments.html#CommunicatingWithActivity.
Bundle args = new Bundle();
args.putParcelable(ARG_VIDEO_SELECTED, mVideoSelected);
fragment.setArguments(args);
Put this variable in 'args' (just a key-value map). Just like:
args.putExtra("id", id);
args.putExtra("parcelable", p)
A cool way to do this is to create a singleton class :
public class Singleton {
private static Singleton mInstance = null;
private int mVar;
private Singleton() {
if (mInstance == null) {
mInstance = new Singleton();
}
return mInstance;
}
public static getInstance () {
return mInstance;
}
public int getVar () {
return mVar;
}
public void setVar (int val) {
mVar = val;
}
}

How to pass/share object from fragment to fragment?

I want to pass realtime object from fragment to fragment.
I dont want to pass data.
I dont found way to do that.
The only way that I think is by intent but I am not sure.
i read about Singleton pattern,interfaces and Bundle,Global varible.
I would like to see example if it is possible to use share/pass object from one fragment to secend fragment. many Thanks.
Passing real objects between activities or fragments can be achieved through implementing model beans Parcelable or Serializable interface.
Parcelable: A Parcel is similar to a Bundle, but is more sophisticated and can support more complex serialization of classes. Applications can implement the Parcelable interface to define application-specific classes that can be passed around, particularly when using Services.
You can see how to implement Parcelable interface in this article here.
public class Foo implements Parcelable {
...
}
Serializable: A serializable interface is java standard serialization. You can read more about it here.
public class Foo implements Serializable {
private static final long serialVersionUID = 0L;
...
}
Suppose you have a class Foo implements Parcelable properly, to put it into Intent in an Activity:
Intent intent = new Intent(getBaseContext(), NextActivity.class);
Foo foo = new Foo();
intent.putExtra("foo", foo);
startActivity(intent);
To get it from intent in another activity:
Foo foo = (Foo) getIntent().getExtras().getParcelable("foo");
** EDIT **
As the original question asked for Fragments, then this is how it works:
Fragment fragment = new Fragment();
Foo foo = new Foo();
Bundle bundle = new Bundle();
bundle.putParcelable("Foo", foo);
fragment.setArguments(bundle);
To get it from bundle in another fragment:
Foo foo = (Foo) bundle.getParcelable("Foo");
Hope this helps!
Pass object from one Fragment to another Fragment can be acheived by using these simple steps:
First of all, you have to make your model class as Parcelable:
class Car implements Parcelable
Then implements the override functions of Parcelable class: e-g
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int i) {
}
From First Fragment:
// Set data to pass
MyFragment fragment = new MyFragment(); //Your Fragment
Car car = new Car(); // Your Object
Bundle bundle = new Bundle();
bundle.putParcelable("carInfo", car) // Key, value
fragment.setArguments(bundle);
// Pass data to other Fragment
getFragmentManager()
.beginTransaction()
.replace(R.id.container, fragment)
.commit();`
On Second Fragment
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = this.getArguments();
if (bundle != null) {
Car receivedCar = bundle.getParcelable("carInfo"); // Key
}
}
Hope it will help :)
There is another method you can pass object by just making a simple setter function.
From your current fragment make object of target fragment. Your target fragment should have a setter function like
public void setObjectFunction(Object obj){this.mObj = obj}
YourFragment yourFragment = new YourFragment();
Object passingObj = new Object();
yourFragment.setObjectFunction(passingObj);
Then
getFragmentManager()
.beginTransaction()
.replace(R.id.container, yourFragment)
.commit();`

Correct usage of fragment in android

I'm sure this question has been asked lots of times but didn't find any useful answer.
I'm trying to implement Fragment which can be use in my app for X times (yes yes..even 100 and more..)
I want to create my fragment only once and in other times to pass bundle and make lifecycle do what he needs to do with the bundle data.
So far so good? So what i've found is a nice implementation from google document:
public static class MyFragment extends Fragment {
public MyFragment() { } // Required empty constructor
public static MyFragment newInstance(String foo, int bar) {
MyFragment f = new MyFragment();
Bundle args = new Bundle();
args.putString(ARG_FOO, foo);
args.putInt(ARG_BAR, bar);
f.setArguments(args);
return f;
}
You can then access this data at a later point:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
// Use initialisation data
}
}
So what's wrong here? First, the Fragment MUST be an inner class. Second, if the class is static, and the function newInstance(...) is static, why they always create new instance without checking (By keeping a static member of the fragment) if it's not null like a Singleton ?
Assuming my fragment will be added many times to my fragment manager, can I use my fragment class as full Singleton? it means that each time I'll call:
public class MyFragment extends Fragment {
private static MyFragment sInstance;
public MyFragment() { } // Required empty constructor
public static MyFragment newInstance(String foo, int bar) {
if (sInstance==null) {
sInstance = new MyFragment();
}
Bundle args = new Bundle();
args.putString(ARG_FOO, foo);
args.putInt(ARG_BAR, bar);
f.setArguments(args);
return f;
}
}
Than use the new/exist fragment to make the transaction.
Hope I make myself clear, and didn't write some nonsense here :)
Thanks very much for your help

Categories

Resources