What's the essential difference between these two methods? When I create a TextView, should I use one over the other for performance?
Edit:
What's the difference from
onCreateView() {
root = some view
View v = new View(some context);
root.add(v);
return root;
}
onViewCreated() {
View v = new View(some context);
getView().add(v);
}
We face some crashes initializing view in onCreateView.
You should inflate your layout in onCreateView but shouldn't initialize other views using findViewById in onCreateView.
Because sometimes view is not properly initialized. So always use findViewById in onViewCreated(when view is fully created) and it also passes the view as parameter.
onViewCreated is a make sure that view is fully created.
onViewCreated android Documentation
Called immediately after onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle) has returned, but before any saved state has been restored in to the view. This gives subclasses a chance to initialize themselves once they know their view hierarchy has been completely created. The fragment's view hierarchy is not however attached to its parent at this point.
onViewCreated is called immediately after onCreateView (the method you initialize and create all your objects, including your TextView), so it's not a matter of performance.
From the developer site:
onViewCreated(View view, Bundle savedInstanceState)
Called immediately after onCreateView(LayoutInflater, ViewGroup, Bundle) has returned, but before any saved state has been restored in to the view. This gives subclasses a chance to initialize themselves once they know their view hierarchy has been completely created. The fragment's view hierarchy is not however attached to its parent at this point.
Source: Fragment#onViewCreated
It's better to do any assignment of subviews to fields in onViewCreated. This is because the framework does an automatic null check for you to ensure that your Fragment's view hierarchy has been created and inflated (if using an XML layout file) properly.
Code snippet from: FragmentManger.java
// This calls onCreateView()
f.mView = f.performCreateView(f.getLayoutInflater(f.mSavedFragmentState), null, f.mSavedFragmentState);
// Null check avoids possible NPEs in onViewCreated
// It's also safe to call getView() during or after onViewCreated()
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
if (f.mHidden) f.mView.setVisibility(View.GONE);
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
onCreateView() is the Fragment equivalent of onCreate() for Activities and runs during the View creation.
onViewCreated() runs after the View has been created.
should I use one over the other for performance? NO. There's no evidence of a performance boost.
There is actually an onCreate() method in Fragments too, but it's rarely used (I do never use it, nor find a good use case for it).
I always use onCreateView() in Fragments as a replacement for onCreate().
And I'm happy with that.
The docs for Fragment.onCreateView() now says:
It is recommended to only inflate the layout in this method and move logic that operates on the returned View to onViewCreated(View, Bundle).
No need for us to understand why; we just need to do as the docs says, but it would be interesting to know why this recommendation exists. My best guess is separation of concern, but IMHO this makes it a little bit more complicated than it has to be.
onCreateView returns the inflated view. OnViewCreated is called just after onCreateView and get has parameter the inflated view. Its return type is void
Ok, so If we are going to talk about onCreateView() and onViewCreated(). It is worth while to talk a little about the fragment lifecycle. The full documentation about the fragment lifecycle can be found HERE, I recommend that you read up on it, as we will only be talking about the states relevant to onCreateView() and onViewCreated().
The fragment lifecycle contains 5 states:
1) INITIALIZED
2) CREATED
3) STARTED
4) RESUMED
5) DESTROYED
The reason that we need to talk about the fragment lifecycle is because both onCreateView() and onViewCreated() get called during the CREATED state in the lifecycle.
So when a fragment is instantiated, it begins in the INITIALIZED state, for example when you see:
CustomFragment frag1 = new CustomFragment() //`INITIALIZED` state
CustomFragment.class //`INITIALIZED` state
The .class syntax is the class literal syntax and for a brief summary I would recommend reading the blog post HERE
For a fragment to transition into other lifecycle states, it must be added to a Fragment Manager.
The Fragment Manager is responsible for determining what state its fragment should be in and then moving them into that state.
Difference between onCreateView() and onViewCreated()
Once the fragment has been added to the Fragment Manager, onAttach() is called to attach the fragment to the host activity.
Once onAttch() is called the fragment enters the CREATED state. It is in this state that the Android system begins creating the fragment's view. This can be done a few ways, for example the documentation states:
In most cases, you can use the fragment constructors that take a #LayoutId, which automatically inflates the view at the appropriate time. You can also override onCreateView() to programmatically inflate or create your fragment's view
If we look at the documentation for onCreateView() we see that:
It is recommended to only inflate the layout in this method and move logic that operates on the returned View to onViewCreated
Conclusion
Now combining everything we can come to the conclusion, both onCreateView() and onViewCreated() are called during the CREATED state of a fragment's life cycle. However, onCreateView() is called first and should only be used to inflate the fragment's view. onViewCreated() is called second and all logic pertaining to operations on the inflated view should be in this method.
i think the main different between these is when you use kotlin.in onCreateView() every Time you want to access to view in your xml file you should use findViewById but in onViewCreated you can simply access to your view just by calling the id of it.
The main reason I would use onViewCreated is since it separates any initialization logic from the view hierarchy inflation/creation logic which should go in the onCreateView . All other performance characteristics look the same.
In the Google Documentation
There is a new solution to declare the xml resource in the Fragment superclass
class ExampleFragment : Fragment(R.layout.example_fragment) { }
Then bind the view in onViewCreate
private lateinit var binding : ExampleFragmentBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = ExampleFragmentBinding.bind(view)
}
In this way you do not need to inflate view in onCreatedView or handle the view in onDestroy
onCreateView is used in fragment to create layout and inflate view.
onViewCreated is used to reference the view created by above method.
Lastly it is a good practice to define action listener in onActivityCreated.
Related
This snippet was used in an activity(onCreate) :
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
This snippet was used in an Fragment(onCreateView) :
cameraView = inflater.inflate(R.layout.fragment_camera_view, container, false)
return cameraView
There are a few reasons to use Binding over direct inflation:
Runtime performance : with direct inflation findViewById() it performs a top-down search of the View hierarchy until it finds a match. It is not optimised, and has no internal cache, so if we make the call that method twice in quick succession with the same View ID, then both invocations will require the same top-down search. While with binding, there is no hidden cost of accessing the text1 field of a ActivityMainBinding instance.
Crash avoidance : sometimes we encounter crashes using Kotlin synthetic view properties if we attempt to access them too early in the Android lifecycle before they have been initialised. While it is still necessary to perform the inflation of the layout and binding at the correct phase of the Android lifecycle, that initialisation will actually be done within the Activity or Fragment code making it much more visible precisely when in the lifecycle the initialisation is taking place.
Build Time : The improvements in runtime performance will incur a cost at build-time because it uses code generation. It will also increase your APK size and method count.
Reference: https://blog.stylingandroid.com/view-binding-internals/
Two separate things really. setContentView is how an Activity displays its view hierarchy. You can either inflate the hierarchy yourself and pass that in (like you're doing here, with binding.inflate and then passing the resulting binding.root), or you can call setContentView(R.layout.some_layout) and it'll take care of inflating that layout itself.
onCreateView is a Fragment method, it gets called when the Fragment is initialising, and it needs to create its view hierarchy. So you need to override this, inflate your hierarchy, and then return it at the end so the Fragment can use it.
So setContentView gets called in an Activity, and can take a layout reference or an actual inflated set of Views. onCreateView is a method in a Fragment where you need to return an inflated set of Views.
When it comes to actually inflating those Views, you have a few options. Your examples are each using a different approach - so on top of one being an Activity and one being a Fragment, where you do things differently, you're also mixing and matching the way you inflate stuff.
The standard way to inflate a layout is to just grab a LayoutInflater and call inflate on it, passing a layout XML file so it can use that as a recipe to create all the necessary View objects and connect them together:
// Typically in an Activity you'd use 'this' as the Context, since an Activity -is- a Context
// In a Fragment's onCreateView you get an inflater passed in, in a RecyclerView.Adapter's
// onCreateViewHolder you have access to the 'parent' which you can grab a Context from, etc
val inflater = LayoutInflater.from(context)
// Inflate an XML file - the second parameter is the parent container, used for working out
// things like layout parameters (e.g. to make 'match_parent' work).
// The last parameter is about attaching the View you're inflating - this is usually false!
// We're handing off the View, the thing that's using it will handle attaching it
val view = inflater.inflate(R.layout.some_layout, container, false)
And that's it! Now you have a bunch of actual Views you can hand over for display.
// in your activity
setContentView(view)
// at the end of onCreateView
return view
If you're using View Binding, you usually don't want to use a LayoutInflater directly. The generated binding class (e.g. ActivityMainBinding) has an inflate call that does the inflation for you using the relevant XML file, and then it creates a binding object with variables for all the View objects in that inflated hierarchy.
That way you don't need to look anything up with findViewById - that's basically already been done for you, and you can access them with binding.someId. The binding object holds the inflated hierarchy too, which you can access with binding.root. You can pass that for display in the same way as before:
// in your activity
setContentView(binding.root)
// at the end of onCreateView
return binding.root
See what I mean? You do things differently in an Activity and a Fragment, but the way you inflate the views can be the same - it just depends on what you're doing, if you're using View Binding then you'll be using the binding class instead of inflater.inflate.
For completeness's sake, you can also take an already-inflated view hierarchy and create a binding object from that, using the bind method - e.g. ActivityMainBinding.bind(view). This is useful if the inflation has already been taken care of, so you want to skip that step and just look up all the views and get your binding object.
Remember, if you inflate a layout again, you get a completely different set of objects, and if you display those you can't see or interact with the original ones. Generally, you only want to inflate a layout once - having two sets of Views is a sign you've made a mistake, and can lead to bugs like "why aren't my click listeners working" (you set them on the other Views that you replaced) etc.
A typical situation where you might have an already-inflated layout is if you're using the Activity and Fragment constructors where you supply a layout XML resource as a parameter, like class MainActivity : AppCompatActivity(R.layout.activity_main). When you call super.onCreate() that takes care of the setContentView bit (and you might not need to override onCreate at all if that's all it does!). To create your binding object, you just need to bind to the Activity's view property.
Same thing for Fragments - you can put the layout file in the constructor, then there's no need to override onCreateView since that's all taken care of. Instead, you can override onViewCreated to do your setup - you get passed the inflated view and you can bind to that in there
I am confused about usage of onCreate(), onCreateView() and getView().
1. Can i use all these three in my activity class?
2. Should i compulsorily have different layouts for each?
Here is description o these methods from Google Developer website:
onCreate()
It gets called when the activity is starting.
This is where most initialization should go:
calling setContentView(int) to inflate the activity's UI,
using findViewById(int) to programmatically interact with widgets in the UI,
calling managedQuery(android.net.Uri, String[], String, String[], String) to retrieve cursors for data being displayed, etc.
OnCreateView()
It is not a lifecycle method for activity.
It's just a member method which will be used for specified tasks as said in doc.
Standard implementation of
android.view.LayoutInflater.Factory.onCreateView used when inflating
with the LayoutInflater returned by getSystemService. This
implementation does nothing and is for
pre-android.os.Build.VERSION_CODES.HONEYCOMB apps. Newer apps should
use onCreateView(View, String, Context, AttributeSet). To rely of call
of onCreateView() in Activity is bad programming.
If you are using this method for Fragments then,
It will be Called to have the fragment instantiate its user interface view.
getView()
This method is available for Fragments only.
It gets the root view for the fragment's layout (the one returned by
onCreateView(LayoutInflater, ViewGroup, Bundle)), if provided.
References:
https://developer.android.com/reference/android/app/Fragment.html#getView()
https://developer.android.com/reference/android/app/Activity.html#onCreate(android.os.Bundle)
first refer Activity Life cycle https://developer.android.com/reference/android/app/Activity.html ,
onCreate() :
Called when the activity is first created. This is where you should do all of your normal static set up: create views, bind data to lists, etc. This method also provides you with a Bundle containing the activity's previously frozen state, if there was one. Always followed by onStart().
second ,refer fragment life cycle https://www.tutorialspoint.com/android/android_fragments.htm
you are confused as onCreate() is both in activity and fragments right!!
let we explore ..
onCreateView() :
The onCreate() method in a Fragment is called after the Fragment's onAttachFragment() but before that Fragment's onCreateView().
In this method, you can assign variables, get Intent extras, and anything else that doesn't involve the View hierarchy (i.e. non-graphical initialisations). This is because this method can be called when the Activity's onCreate() is not finished, and so trying to access the View hierarchy here may result in a crash.
Third ,refer adapters ,http://www.edureka.co/blog/what-are-adapters-in-android/
getView() :
1: The LayoutInflater takes your layout XML-files and creates different View-objects from its contents.
2: The adapters are built to reuse Views, when a View is scrolled so that is no longer visible, it can be used for one of the new Views appearing. This reused View is the convertView. If this is null it means that there is no recycled View and we have to create a new one, otherwise we should use it to avoid creating a new.
3: The parent is provided so you can inflate your view into that for proper layout parameters.
All these together can be used to effectively create the view that will appear in your list (or other view that takes an adapter):
public View getView (int position, View convertView, ViewGroup parent){
if( convertView == null ){
//We must create a View:
convertView = inflater.inflate(R.layout.my_list_item, parent, false);
}
//Here we can do changes to the convertView, such as set a text on a TextView
//or an image on an ImageView.
return convertView;
}
You can not use onCreateView() and getView() inside your activity (in case of custom adapter if you wish ,you can create custom adapter inside your activity and in that class you can use getView()).
What's the essential difference between these two methods? When I create a TextView, should I use one over the other for performance?
Edit:
What's the difference from
onCreateView() {
root = some view
View v = new View(some context);
root.add(v);
return root;
}
onViewCreated() {
View v = new View(some context);
getView().add(v);
}
We face some crashes initializing view in onCreateView.
You should inflate your layout in onCreateView but shouldn't initialize other views using findViewById in onCreateView.
Because sometimes view is not properly initialized. So always use findViewById in onViewCreated(when view is fully created) and it also passes the view as parameter.
onViewCreated is a make sure that view is fully created.
onViewCreated android Documentation
Called immediately after onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle) has returned, but before any saved state has been restored in to the view. This gives subclasses a chance to initialize themselves once they know their view hierarchy has been completely created. The fragment's view hierarchy is not however attached to its parent at this point.
onViewCreated is called immediately after onCreateView (the method you initialize and create all your objects, including your TextView), so it's not a matter of performance.
From the developer site:
onViewCreated(View view, Bundle savedInstanceState)
Called immediately after onCreateView(LayoutInflater, ViewGroup, Bundle) has returned, but before any saved state has been restored in to the view. This gives subclasses a chance to initialize themselves once they know their view hierarchy has been completely created. The fragment's view hierarchy is not however attached to its parent at this point.
Source: Fragment#onViewCreated
It's better to do any assignment of subviews to fields in onViewCreated. This is because the framework does an automatic null check for you to ensure that your Fragment's view hierarchy has been created and inflated (if using an XML layout file) properly.
Code snippet from: FragmentManger.java
// This calls onCreateView()
f.mView = f.performCreateView(f.getLayoutInflater(f.mSavedFragmentState), null, f.mSavedFragmentState);
// Null check avoids possible NPEs in onViewCreated
// It's also safe to call getView() during or after onViewCreated()
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
if (f.mHidden) f.mView.setVisibility(View.GONE);
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
onCreateView() is the Fragment equivalent of onCreate() for Activities and runs during the View creation.
onViewCreated() runs after the View has been created.
should I use one over the other for performance? NO. There's no evidence of a performance boost.
There is actually an onCreate() method in Fragments too, but it's rarely used (I do never use it, nor find a good use case for it).
I always use onCreateView() in Fragments as a replacement for onCreate().
And I'm happy with that.
The docs for Fragment.onCreateView() now says:
It is recommended to only inflate the layout in this method and move logic that operates on the returned View to onViewCreated(View, Bundle).
No need for us to understand why; we just need to do as the docs says, but it would be interesting to know why this recommendation exists. My best guess is separation of concern, but IMHO this makes it a little bit more complicated than it has to be.
onCreateView returns the inflated view. OnViewCreated is called just after onCreateView and get has parameter the inflated view. Its return type is void
Ok, so If we are going to talk about onCreateView() and onViewCreated(). It is worth while to talk a little about the fragment lifecycle. The full documentation about the fragment lifecycle can be found HERE, I recommend that you read up on it, as we will only be talking about the states relevant to onCreateView() and onViewCreated().
The fragment lifecycle contains 5 states:
1) INITIALIZED
2) CREATED
3) STARTED
4) RESUMED
5) DESTROYED
The reason that we need to talk about the fragment lifecycle is because both onCreateView() and onViewCreated() get called during the CREATED state in the lifecycle.
So when a fragment is instantiated, it begins in the INITIALIZED state, for example when you see:
CustomFragment frag1 = new CustomFragment() //`INITIALIZED` state
CustomFragment.class //`INITIALIZED` state
The .class syntax is the class literal syntax and for a brief summary I would recommend reading the blog post HERE
For a fragment to transition into other lifecycle states, it must be added to a Fragment Manager.
The Fragment Manager is responsible for determining what state its fragment should be in and then moving them into that state.
Difference between onCreateView() and onViewCreated()
Once the fragment has been added to the Fragment Manager, onAttach() is called to attach the fragment to the host activity.
Once onAttch() is called the fragment enters the CREATED state. It is in this state that the Android system begins creating the fragment's view. This can be done a few ways, for example the documentation states:
In most cases, you can use the fragment constructors that take a #LayoutId, which automatically inflates the view at the appropriate time. You can also override onCreateView() to programmatically inflate or create your fragment's view
If we look at the documentation for onCreateView() we see that:
It is recommended to only inflate the layout in this method and move logic that operates on the returned View to onViewCreated
Conclusion
Now combining everything we can come to the conclusion, both onCreateView() and onViewCreated() are called during the CREATED state of a fragment's life cycle. However, onCreateView() is called first and should only be used to inflate the fragment's view. onViewCreated() is called second and all logic pertaining to operations on the inflated view should be in this method.
i think the main different between these is when you use kotlin.in onCreateView() every Time you want to access to view in your xml file you should use findViewById but in onViewCreated you can simply access to your view just by calling the id of it.
The main reason I would use onViewCreated is since it separates any initialization logic from the view hierarchy inflation/creation logic which should go in the onCreateView . All other performance characteristics look the same.
In the Google Documentation
There is a new solution to declare the xml resource in the Fragment superclass
class ExampleFragment : Fragment(R.layout.example_fragment) { }
Then bind the view in onViewCreate
private lateinit var binding : ExampleFragmentBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = ExampleFragmentBinding.bind(view)
}
In this way you do not need to inflate view in onCreatedView or handle the view in onDestroy
onCreateView is used in fragment to create layout and inflate view.
onViewCreated is used to reference the view created by above method.
Lastly it is a good practice to define action listener in onActivityCreated.
I can't seem to find any use cases of this, and Android Developers isnt being too clear about it. I get that to access an activities UI elements from a Fragment I need to call getActivity.findViewById, and to access the fragments from an Activity its getFragment.findFragmentById. But for the activity, can i just call findViewById if the Fragments is attached to the activity without calling anything else? Essentially, does an Activity automatically know the view IDs of contained Fragments UI elements.
findViewById() simply traverses the layout to find a view with that ID. When a Fragment is attached to an Activity, it is added to that Activity's layout. So yes, you can access a Fragment's views via their IDs from an Activity, but I would highly recommend against it. Add a public method on your Fragment that lets you make whatever change to those views that is desired, instead. This way you have the freedom to change your layout without worrying about breaking the host Activity.
Also, you don't need to use getActivity().findViewById() within a Fragment -- simply override onViewCreated(), and call findViewById() on the provided view instance. Or at any point in the lifecycle between onCreateView() and onDestroyView() you can use getView().findViewById().
For example:
public void onViewCreated(View view, Bundle savedInstanceState) {
TextView fragmentTextView = (TextView) view.findViewById(R.id.textview_in_fragment);
}
This is really a two questions pertaining to lifecycle.
1) In Fragment.onCreateView(LayoutInflater, ViewGroup container, Bundle), all of the examples I've seen simply use the LayoutInflater to inflate a View, and return it. If this is part of a Restore though, i.e. non-null Bundle, shouldn't the restoration of the view hierarchy be handled by the system? Should I instead be calling container.findViewById() or trying to pull the view out of the Bundle or something (for the purposes of pulling out references to subviews)?
2) In general, do any of the Fragment lifecycle callbacks need to worry about saving/restoring the state of its view hierarchy, even implicitly by calling super.onXXX()? Or is that all handled uplevel by the owning Activity when it calls super.onCreate(Bundle)?
Although the framework is responsible for re-creating the Fragment itself, the view hierarchy must be recreated manually. Views cannot survive the destruction of their Activity (plus, since onCreateView() has your implementation, you could conditionally inflate another layout or do different things -- that's why it has to run every time). The Bundle contains information put there by onSaveInstanceState(), but the old views are not part of it.
If the view ids match between the old and new layout, then the state should be automatically restored (via the super calls). Views override their own onSaveInstanceState() for this. If you save your custom state in the fragment's onSaveInstanceState(), then you're also responsible for restoring it.