Search code examples
androidandroid-activityviewlifecycle

How can Activity and its Views lifecycles overlap in android


There are two lifecycles in android basically an Activity lifecycle and a View LifeCycle but at which phase of the activity lifecycle does the View LifeCycle kick in? And from the moment the View Lifecycle kicks in, does it go all the way through it's lifecycle or it gets completed on various parts of the Activity Lifecycle? (If so, then please mention which methods get invoked in which parts)


Solution

  • Hereby is a not a 100% official diagram which is I mix from the official activity life cycle diagram and view life cycle, As I didn't see any diagrams in the android documentation about view life cycle (in case we can call it a life cycle).

    enter image description here

    So, in the diagram, the orange arrows are added as of the observation of the following demo app that is just for demonstrating the relationship of both life cycles; where I created a dummy custom TextView and logged its super class life cycle methods along with its holding activity life cycle methods; and add the orange arrows accordingly.

    So, as in the diagram, the activity is created by its onCreate() and just after the activity's layout is inflated by setContentView(), the system calls the constructors of your layout views in order to construct them.

    Now the activity is just created and views' instances are built; and still nothing visible on the screen; so then the activity's onStart(), & onResume() methods are called respectively, and hence the activity is now visible on the screen; and still nothing is drawn on it.

    Then, when the activity's window has been attached to the window manager, the activity's onAttachedToWindow() is called, firing a green light to underlying views to be drawn on the activity.

    At this point the activity's life is considered in running/active state. Following activity'sonAttachedToWindow(), the view's onAttachedToWindow() is called when it's attached to the activity's window, and now the view can start drawing on the screen.

    Drawing a view on the screen passes by a series of calls to determine some measurements like sizing and attributes; stuff like width, height, colors, text, padding etc.. this requires to call measure() a few times; and subsequently onMeasure() is called

    Eventually, onDraw() is called which has a canvas argument that serves as the target surface of drawing the view.

    You can find the rest of drawing associated methods that are depicted on the graph, and you can dive into them in here.

    When the activity is destroyed with onDestroy(), then before the activity's main window is detached from the window manager, the underlying views will first take the chance to detach from the activity's window; and when that in place, the view's onDetachedFromWindow() is called to declare that it is removed from the screen, and hence the activity can now be detached from the window manager; when that happens, the activity's onDetachedFromWindow() will be called accordingly.

    As a result, the activity won't be detached from the window manager unless all views are detached from the window first.

    So, there is no something on a view like onDestroy(), views can attach or detach from the activity's window; you can check this answer for that. In addition onDetachedFromWindow() of the views is highly coupled with their activity's onDestroy(), where if the activity's onStop() is called, the view is still attached to the activity's window.

    So, there is no such thing that we can call a view is destroyed, but a view is detached.

    Note also that the onAttachedToWindow() of the activity & views is very coupled to onCreate() of the activity; so when the onRestart() of the activity is called, the activity & its views are already associated with the window, so onAttachedToWindow() is not called (This is not clear much on the diagram).

    Similarly, onDetachedFromWindow() of views & activity is tied only with onDestroy(); so when the activity is paused or stopped, the onDetachedFromWindow() won't call and hence views are still attached to the window.

    You can also play with parentLayout.removeView(customView); and observe the callbacks.

    Below is the demo example that is used to pursue this observation

    Layout

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical">
    
        <com.example.android.androidxtest.CustomTextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/long_text"
            android:textSize="22sp" />
    
    </LinearLayout>
    

    Activity

    public class LifeCycleActivity extends AppCompatActivity {
    
        private static final String TAG = "LOG_TAG_ACTIVITY";
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Log.d(TAG, "onCreate: ");
            setContentView(R.layout.activity_view_lifecycle);
            Log.d(TAG, "onCreate: after setContentView()");
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            Log.d(TAG, "onPause: ");
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            Log.d(TAG, "onDestroy: ");
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            Log.d(TAG, "onResume: ");
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            Log.d(TAG, "onStop: ");
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            Log.d(TAG, "onStart: ");
        }
    
        @Override
        protected void onRestart() {
            super.onRestart();
            Log.d(TAG, "onRestart: ");
        }
    
    
        @Override
        public void onAttachedToWindow() {
            super.onAttachedToWindow();
            Log.d(TAG, "onAttachedToWindow: ");
        }
    
        @Override
        public boolean isDestroyed() {
            Log.d(TAG, "isDestroyed: ");
            return super.isDestroyed();
        }
    
        @Override
        public void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            Log.d(TAG, "onDetachedFromWindow: ");
        }
    
    
    }
    

    Custom View

    public class CustomTextView extends TextView {
    
        private static final String TAG = "LOG_TAG_VIEW";
    
        public CustomTextView(Context context) {
            super(context);
            Log.d(TAG, "CustomTextView: Constructor");
        }
    
        public CustomTextView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            Log.d(TAG, "CustomTextView: Constructor");
        }
    
        public CustomTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            Log.d(TAG, "CustomTextView: Constructor");
        }
    
        public CustomTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
            Log.d(TAG, "CustomTextView: Constructor");
        }
    
        @Override
        protected void onAttachedToWindow() {
            super.onAttachedToWindow();
            Log.d(TAG, "onAttachedToWindow: ");
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            Log.d(TAG, "onMeasure: ");
        }
    
        @Override
        public void layout(int l, int t, int r, int b) {
            super.layout(l, t, r, b);
            Log.d(TAG, "layout: ");
        }
    
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
            Log.d(TAG, "onLayout: ");
        }
    
        @Override
        protected void dispatchDraw(Canvas canvas) {
            super.dispatchDraw(canvas);
            Log.d(TAG, "dispatchDraw: ");
        }
    
        @Override
        public void draw(Canvas canvas) {
            super.draw(canvas);
            Log.d(TAG, "draw: ");
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            Log.d(TAG, "onDraw: ");
        }
    
        @Override
        protected void onDetachedFromWindow() {
            super.onDetachedFromWindow();
            Log.d(TAG, "onDetachedFromWindow: ");
        }
    
    }
    

    Log on app launch

    2020-02-25 14:09:41.859 2043-2043/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onCreate: 
    2020-02-25 14:09:41.945 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: CustomTextView: Constructor
    2020-02-25 14:09:41.945 2043-2043/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onCreate: after setContentView()
    2020-02-25 14:09:41.947 2043-2043/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onStart: 
    2020-02-25 14:09:41.954 2043-2043/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onResume: 
    2020-02-25 14:09:41.984 2043-2043/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onAttachedToWindow: 
    2020-02-25 14:09:41.985 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: onAttachedToWindow: 
    2020-02-25 14:09:41.993 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: onMeasure: 
    2020-02-25 14:09:42.005 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: onMeasure: 
    2020-02-25 14:09:42.006 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: onLayout: 
    2020-02-25 14:09:42.006 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: layout: 
    2020-02-25 14:09:42.032 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: onDraw: 
    2020-02-25 14:09:42.032 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: dispatchDraw: 
    2020-02-25 14:09:42.032 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: draw: 
    

    Log on menu button (app's history)

    2020-02-25 13:44:44.462 32357-32357/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onPause: 
    2020-02-25 13:44:44.511 32357-32357/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onStop: 
    

    Log on back to our app from the menu button (app's history)

    2020-02-25 14:11:23.387 2043-2043/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onRestart: 
    2020-02-25 14:11:23.392 2043-2043/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onStart: 
    2020-02-25 14:11:23.394 2043-2043/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onResume: 
    2020-02-25 14:11:23.405 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: onMeasure: 
    2020-02-25 14:11:23.420 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: onLayout: 
    2020-02-25 14:11:23.420 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: layout: 
    2020-02-25 14:11:23.424 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: onDraw: 
    2020-02-25 14:11:23.424 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: dispatchDraw: 
    2020-02-25 14:11:23.424 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: draw: 
    2020-02-25 14:11:23.455 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: onMeasure: 
    2020-02-25 14:11:23.460 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: onMeasure: 
    2020-02-25 14:11:23.460 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: onLayout: 
    2020-02-25 14:11:23.460 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: layout: 
    2020-02-25 14:11:23.461 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: onDraw: 
    2020-02-25 14:11:23.461 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: dispatchDraw: 
    2020-02-25 14:11:23.462 2043-2043/com.example.android.androidxtest D/LOG_TAG_VIEW: draw: 
    

    Log on configuration change (rotation)

    2020-02-25 17:05:00.481 8058-8058/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onPause: 
    2020-02-25 17:05:00.492 8058-8058/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onStop: 
    2020-02-25 17:05:00.493 8058-8058/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onDestroy: 
    2020-02-25 17:05:00.512 8058-8058/com.example.android.androidxtest D/LOG_TAG_VIEW: onDetachedFromWindow: 
    2020-02-25 17:05:00.517 8058-8058/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onDetachedFromWindow: 
    2020-02-25 17:05:00.563 8058-8058/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onCreate: 
    2020-02-25 17:05:00.600 8058-8058/com.example.android.androidxtest D/LOG_TAG_VIEW: CustomTextView: Constructor
    2020-02-25 17:05:00.601 8058-8058/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onCreate: after setContentView()
    2020-02-25 17:05:00.604 8058-8058/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onStart: 
    2020-02-25 17:05:00.611 8058-8058/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onResume: 
    2020-02-25 17:05:00.626 8058-8058/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onAttachedToWindow: 
    2020-02-25 17:05:00.626 8058-8058/com.example.android.androidxtest D/LOG_TAG_VIEW: onAttachedToWindow: 
    2020-02-25 17:05:00.629 8058-8058/com.example.android.androidxtest D/LOG_TAG_VIEW: onMeasure: 
    2020-02-25 17:05:00.659 8058-8058/com.example.android.androidxtest D/LOG_TAG_VIEW: onMeasure: 
    2020-02-25 17:05:00.659 8058-8058/com.example.android.androidxtest D/LOG_TAG_VIEW: onLayout: 
    2020-02-25 17:05:00.660 8058-8058/com.example.android.androidxtest D/LOG_TAG_VIEW: layout: 
    2020-02-25 17:05:00.674 8058-8058/com.example.android.androidxtest D/LOG_TAG_VIEW: onDraw: 
    2020-02-25 17:05:00.674 8058-8058/com.example.android.androidxtest D/LOG_TAG_VIEW: dispatchDraw: 
    2020-02-25 17:05:00.674 8058-8058/com.example.android.androidxtest D/LOG_TAG_VIEW: draw: 
    

    On back pressed

    2020-02-25 16:10:24.743 7314-7314/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onPause: 
    2020-02-25 16:10:25.341 7314-7314/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onStop: 
    2020-02-25 16:10:25.343 7314-7314/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onDestroy: 
    2020-02-25 16:10:25.343 7314-7314/com.example.android.androidxtest D/LOG_TAG_VIEW: onDetachedFromWindow: 
    2020-02-25 16:10:25.344 7314-7314/com.example.android.androidxtest D/LOG_TAG_ACTIVITY: onDetachedFromWindow: