The Life Cycle of a View in Android
Explore & get familiarity with the lifecycle of View to create best performance Custom Views
When we look at an app the first thing that comes to our mind is what we see on the screen. A view is what appears on the screen.
View class represents the basic building block for user interface components. A View occupies a rectangular area on the screen and is responsible for drawing and event handling. The view is the base class for widgets, which are used to create interactive UI components (buttons, text fields, etc.). The ViewGroup subclass is the base class for layouts, which are invisible containers that hold other Views (or other ViewGroups) and define their layout properties.
View Life Cycle
Every Activity has it’s own life cycle similarly Views also have a Life Cycle. A view which was rendered on the screen must undergo these lifecycle methods to get drawn on the screen correctly. Each of these methods has its importance. Let’s dive into the life cycle.
Constructors
Usually, we get confused about why there are four types of constructors for a View
View(Context context) View(Context context, @Nullable AttributeSet attrs) View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)
View(Context context)
Simple constructor to use when creating a view from code dynamically. Here the parameter context is the Context in which the view is running in, through which it can access the current theme, resources, etc.
View(Context context, @Nullable AttributeSet attrs)
Constructor that is called when inflating a view from XML. This is called when a view is being constructed from an XML file, supplying attributes that were specified in the XML file. This version uses a default style of 0, so the only attribute values applied are those in the Context’s Theme and the given AttributeSet.
View(Context context, @Nullable AttributeSet attrs, int defStyleAttr)
Perform inflation from XML and apply a class-specific base style from a theme attribute. This constructor of View allows subclasses to use their own base style when they are inflating. For example, a Button class’s constructor would call this version of the super class constructor and supply R.attr.buttonStyle for defStyleAttr ; this allows the theme’s button style to modify all of the base view attributes (in particular its background) as well as the Button class’s attributes
The parameter defStyleAttr is an attribute in the current theme that contains a reference to a style resource that supplies default values for the view. It can be 0 to not look for defaults.
View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)
Perform inflation from XML and apply a class-specific base style from a theme attribute or style resource. This constructor of View allows subclasses to use their own base style when they are inflating. Similar to the above one.
The parameter defStyleRes A resource identifier of a style resource that supplies default values for the view, used only if defStyleAttr is 0 or can not be found in the theme. It can be 0 to not look for defaults.
Life of a View is mainly made of three things :
Attachment / Detachment
Traversals
State Save / Restore
Attachment / Detachment
This is the phase that when a view is attached or detached from the window. In this phase, we have some methods in which we receive the callbacks to do appropriate things.
onAttachedToWindow()
Called when the view is attached to a window. This is the phase where the view knows it can be active and has a surface for drawing. So we can start allocating any resources or set up listeners.
onDetachedFromWindow()
This is called when the view is detached from a window. At this point, it no longer has a surface for drawing. This place where you need to stop doing any kind of work that is scheduled or clean up resources that are allocated. This method is called when we call remove view on the ViewGroup or when the activity is destroyed etc…
onFinishInflate()
This method will be called after all children have been added
Traversals
This is called the Traversals phase because the view hierarchy is like a tree structure from the parent node(ViewGroup) with branches to the leaf nodes(Child views). So each method starts from parent and traverses till the last node to define the constraints.


The Measure phase and the Layout phase always happen together. It was a sequential process as shown above.
onMeasure()
This is called to find out how big a view should be. In the case of ViewGroup, it will go ahead and call measure on each of their child views and the results can help to decide its own size.
onMeasure(int widthMeasureSpec, int heightMeasureSpec)@param widthMeasureSpec Horizontal space requirements as imposed by the parent@param heightMeasureSpec Vertical space requirements as imposed by the parent
onMeasure() doesn’t return a value instead we call setMeasuredDimension() to set width and height explicitly.
MeasureSpec
A MeasureSpec encapsulates the layout requirements passed from parent to child. Each MeasureSpec represents a requirement for either the width or the height. A MeasureSpec is comprised of a size and a mode. There are three possible modes:
MeasureSpec.EXACTLY : The parent has determined an exact size for the child. The child is going to be given those bounds regardless of how big it wants to be. Instances specifying fixed width to a view or weights in LinearLayout or match_parent attribute etc.
MeasureSpec.AT_MOST: The child can be as large as it wants up to the specified size.
MeasureSpec.UNSPECIFIED: The parent has not imposed any constraint on the child. It can be whatever size it wants.
onLayout()
This is called after measuring the views to position them on the screen.
onDraw()
Sizes and positions are calculated in previous steps, so the view can draw itself based on them. In onDraw(Canvas canvas) Canvas object generated (or updates) has a list of OpenGL-ES commands (displayList) to send to the GPU. Never create objects in onDraw() as it gets called a number of times.
There are two more methods that come in to play when there was a change in properties of a particular view. Those are:
invalidate()
invalidate() is a method that insists on force reDrawing of a particular view that we wish to show changes. Simply we can say invalidate() needs to be called when there was a change in view’s appearance.
requestLayout()
At some point, there is a state change in the view. requestLayout() is the signal to the view system that it needs to recalculate the Measure and Layout phase of the views (measure → layout → draw). Simply we can say requestLayout() needs to be called when there was a change in view’s bounds.
You must always be on the UI thread when calling any method on any view. If you are doing work on other threads and want to update the state of a view from that thread, you should use a Handler
State Save / Restore
onSaveInstanceState()
To save the state of view firstly you need to give an ID for it. If your view hierarchy has multiple views with the same ID all of their states get saved so to eliminate this maintain unique IDs.
Secondly, you need a class to extend View.BaseSavedState and then save their properties. An example has been illustrated below for better understanding.
onRestoreInstanceState(Parcelable state)
Here we need to override this method and read the data from Parcelable and later write the logic based on the data available from Parcelable.
Well,
We now have a better idea regarding lifecycle of views.
Please let me know your suggestions and comments.
You can find me on Medium and LinkedIn …
Thank you for reading.