What is difference between 'new Fragment()' and 'Fragment.getInstance()' in Android? - android

In android programming,
When we add fragment to specific layout,
we can use following code snippet
Fragment fragment = new SampleFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_layout, fragment);
fragmentTransaction.commit();
or
Fragment fragment = SampleFragment.getInstance();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_layout, fragment);
fragmentTransaction.commit();
I cannot understand what is difference between that fragment object define sentence.
From some sources, when use 'Fragment.getInstance()' like singleton pattern, pass bundle data to fragment with 'getInstance(Bundle data)' method parameter.
Could you tell me what difference?

getInstance() for Fragment instantiation is a familiar design pattern, which encapsulate the creation of the fragment and its arguments. It means basically that the Fragment is responsible on creating its own instance and should be cleaner and safer than calling only new Fragment(), since you can pass additional data/bundle and "force" the user to use this method. Notice that you are still calling new Fragment() in the getInstance() method, it does not replace it.
public static SomeFragment newInstance(int a, boolean b) {
SomeFragment someFragment = new SomeFragment();
Bundle args = new Bundle();
args.putInt("a", a);
args.putBoolean("b",b);
.....
someFragment.setArguments(args);
return someFragment;
}
that way you will have only one place you would create the parameters bundle and not every time you want to instantiate the fragment.

First thing to note is that if the system destroyed your fragment and has to re-create it, it will call the constructor with no-args. This thing implies that you have to save your arguments somewhere to be used later (You can't create a constructor with args).
Now, let's get back to your question. For the moment, the 2 blocks of code are almost identical, but only for the example you provided. If you should pass some params to your fragment, things are a little different. The getInstance should add the needed arguments to your fragment, guaranteeing that they will be available in a future moment.
Personally, I use the getInstance/newInstance (you may find variation of it, right now, creating a template fragment in Android Studio use the newInstance) method passing the parameters that I need in that fragment. For example, if I need two strings in that fragment, I will pass them to getInstance method
and save them in the fragment arguments to make sure that they will be available if the fragment is re-created.
public static MyFragment getInstance(String param1, String param2) {
MyFragment fragment = new MyFragment();
Bundle args = new Bundle();
args.putString(KEY_ONE, param1);
args.putString(KET_TWO, param2);
fragment.setArguments(args);
return fragment;
}
Of course, for this method you can pass a Bundle, but I think that is a little bit clearer in this way, specifying each parameter the fragment will use.
That being said, if you want to create an equivalent of the above block you should use something like this:
MyFragment fragment = new MyFragment();
Bundle args = new Bundle();
// set your arguments here
fragment.setArguments(args);
// and from here use your code as you did
To conclude, using getInstance is used to stop the code repetition (note that if you should create the fragment 10 times, you should copy the above code 10 times) and, if you create the fragment correctly (second block of code) you don't really have to use the getInstance method, but it's recommended.

Related

How to transfer data from one activity to a fragment with Firebase?

Hey I was wondering how I could transfer data from one activity to a fragment using fire base. I have edit text in the activity class and a list view in the Fragment.
I would like to display the information throughout the app database so that other users can see and edit the information too.
I dont know if the IDE matters but passing information to a fragment is usually done with fragment arguments. You need to create a static "newInstance" method in your fragment that you can call from the activity and pass whatever info to the fragment through it. Something like this:
public static mListFragment newInstance(String fromActivity) {
mListFragment fragment = new mListFragment ();
Bundle args = new Bundle();
args.putString("STIRNG_FROM_ACTIVITY", fromActivity);
fragment.setArguments(args);
return fragment;
}
You can then call the method from the activity like this:
FragmentManager fm = getFragmentManager().beginTransaction();
mListFragment fragment = new mListFragment();
fragment = mListFragment.newInstance("info_to_send");
fragmentTransaction.add(R.id.fragments_frame, fragment);
From here you can even persist the info across device screen orientation changes..
Just use firebaseRef to setValue() and set the value from the edittext.
Add ValueListener on the fragment to get the same value from dataSnapshot.
:D
https://github.com/firebase/quickstart-java/tree/master/database/src/main/java/com/google/firebase/quickstart

Passing arguments bundle to Fragment

I need to pass some variable from activity to fragment inside a tab layout. I found there are 2 preferred ways of passing argument bundles to the fragment by its initialization methods for the tab layout.
By creating static newInstance() method and providing details.
Creating instance of fragment inside FragmentPagerAdapter
But, I have some doubts how this works.
If I create this this is:
public class SectionsPagerAdapter extends FragmentPagerAdapter {
MyFragment myFragment;
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
myFragment = new MyFragment();
Bundle args = new Bundle();
args.putString("id", id);
myFragment.setArguments(args);
}
// ...
}
Here I am creating the instance of fragment and setting its argument afterwords.
And if I create it in newInstance() method something like this:
public static MyFragment newInstance(String id) {
MyFragment myFragment = new MyFragment();
Bundle args = new Bundle();
args.putString("id", id);
myFragment.setArguments(args);
return myFragment;
}
Some doubts:
When will the onCreate() or onCreateView() will be called? What if after line new MyFragment() and before setting bundle?
Is there any possibility where getArguments can return null?
In both ways I am doing the same thing. Setting args after new MyFragment() call. How late I can set the arguemnts. Is it necessary to set arguments exactly after the new MyFragment() call?
Sorry, if I asked some silly question. But I am new to Fragments. Thanks :)
onCreate() and onCreateView() will be called sometime after you've committed the fragment transaction. i.e. called commit(). And you set bundle before that.
As long as you're setting bundle before commit, getArguments shouldn't be null.
Both are doing the same thing. In 1st you're creating the fragment instance by yourself and setting bundle yourself. In 2nd you're using what is called a factory method (Effective Java Item 2) which is managed by your fragment. So it's difficult to make mistake in 2nd as arguments are always set.

Pass parameter from activity to fragment

I have an activity that calls to a web service and I want to pass these result to a fragment. Obviously the web service is invoked by an AsyncTask, so the fragment is loaded before getting result.
How can I pass this paramteter from activity's AsyncTask to fragment when is received?
You can implement a method inside your Fragment and call it when needed. For bidirectional communication between an Activity and a Fragment see http://developer.android.com/training/basics/fragments/communicating.html
Set bundle in your fragment.
Bundle args = new Bundle();
args.putInt("id",value);
Fragment newFragment = new Fragment();
newFragment.setArguments(args);
In your fragment get the bundle as
Bundle b = getArguments();
String s = b.getInt("id");
You could move the AsyncTask into the fragment.
But if you wish to keep your current set up, you should save the Fragment reference when you initialize it, and create a public function in the fragment that takes the new data as a parameter.
So the activity code could look like this:
MyFragment fragment = new MyFragment();
getFragmentManager().beginTransaction().replace(android.R.id.content, fragment).commit();
and then you could call:
fragment.updateData(myNewData);
Just make sure to do the appropriate null-checks, just to be safe.

Android Fragments sharing info ways

i have a internal discussion about what way is better to share info between fragments contents inside a controller activity. In a first classical way, you can set arguments when you are going to replace fragments as follows:
//Just now i'm inside Fragment 1 and i'll navigate to Fragment 2
Fragment newFragment = getFragmentManager().findFragmentByTag(Fragment2.TAG);
Bundle b = new Bundle();
b.putBoolean("test1", true);
// Create new fragment and transaction
if(newFragment==null)
newFragment = Fragment2.newInstance(b);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)//.setCustomAnimations(R.anim.enter_anim, R.anim.exit_anim)
.replace(R.id.fragment_place, newFragment, Fragment2.class.getName())
.addToBackStack(newFragment.getClass().getName())
.commit();
The newInstace method does as i meant above, so, with setArguments:
public static Fragment2 newInstance(Bundle arguments){
Fragment2 f = new Fragment2();
if(arguments != null){
f.setArguments(arguments);
}
return f;
}
But Fragment1 and Fragment2 they are both inside a ControllerActivity, so i can also think about a second way to share information obtained in Fragment1 towards Fragment2, through declaring attributes in the ControllerActivity, so i could do (declaring previously an object in the activity) as follows inside any fragment:
EDIT
public class ControllerActivity extends FragmentActivity{
int value = 5;
...
And then, inside my fragment:
((SplashActivity)getActivity()).value = 10; //i can assign or recover value when i desire
My question is what inconveniences would have doing as the second way.
Writing code using 2nd way is fast. But the problem is you have to cast the general Activity to the more specific SplashActivity in which the value variable exists. If you want to use the Fragment with another Activity, or you want a Fragment to be a general purpose UI component you have to use interface for passing the data.
As mentioned in comments, bellow links provide more details about interface/callback method:
android docs
video from slidenerd
Hope this answers your question.

Android activity with ListView open fragment on item click

I have an Activity with ListView, when clicking on a list item opens a new fragment.
Do I need to create a new fragment every time like this?
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.root_layout,new MyFragment());
Or will be enough to create a fragment once and then use it?
in activity:
MyFragment myFragment = new MyFragment();
......
in onItemClickListener:
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.root_layout,myFragment);
It depends on your case. In most cases every list item opens a different fragment (with different data). Then you have to make a static newInstance(Data mySerializableData) method in your fragment, use default constructor inside of it, pass data over Fragment arguments See DetailFragment and use fragmentTransaction.replace() in your activity to add this fragment.
When you dont want your fragment to be changed you can create it only once as you say but there is no need of adding it on every item click. So one creation and only one add.
No, you don't need to create it every time. First, instead of using "add", use "replace". If there is no fragment in fragment manager, your fragment will be added, instead it will be replaced. If you use "add", then you could accidentally add more than one fragment.
You should check for the fragment in the fragment manager and call methods for content updates.
Example:
myFragment = (MyFragment) fragmentManager.findFragmentById(R.id.my_fragment);
if (myFragment == null) {
myFragment = MyFragment.getInstance(someDataIfNeeded);
fragmentManager.beginTransaction().replace(R.id.my_fragment, myFragment).commit();
} else {
myFragment.updateFragmentContent(someData);
}
check instance of that fragment everytime like this-
In your fragment class -
public static final MyFragment newInstance()
{
MyFragment f = new MyFragment();
return f;
}
and in your activity when you want to create fragment -
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.root_layout,MyFragment.newInstance());
this is well n good manner...

Categories

Resources