[Android] Lifecycle - View

HEETAE HEO·2022년 5월 20일
0

Lifecycle

목록 보기
3/3
post-thumbnail

이 글의 목표는 View의 생명 주기를 탐색하고 최상의 성능을 내는 Custom View를 생성하는 것입니다.

일단 View란? : 우리가 앱을 볼 때 가장 먼저 떠오르는 것은 화면에 보이는 것입니다. View는 화면에 나타나는 것을 말합니다.

View 클래스는 사용자 인터페이스 구성 요송의 기본 빌딩 블록을 나타냅니다.
View는 화면의 직사각형 영역을 차지하며 그리기 및 이벤트 처리를 담당합니다. View는 대화형 UI 구성요소(Button, TextField , etc)를 만드는데 사용되는 위젯의 기본 클래스입니다. ViewGroup 하위 클래스는 다른 보기(또 다른 ViewGroup)를 보유하고 해당 레이아웃 속성을 정의하는 보이지 않는 컨테이너인 레이아웃의 기본 클래스입니다.

이미지 - View 클래스 구조도

앞의 글에서 Activity와 Fragment가 각각의 생명주기를 가지고 있는 것처럼 View또한 생명주기를 가지고 있습니다.

생성자의 유형은 4가지인데

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)

: 코드에서 동적으로 View를 생성할 때 사용할 간단한 생성자입니다. 여기에서 매개 변수 Context는 View가 실행 중인 Context이며 이를 통해 현재 테마, 리소스 등에 액세스가 가능합니다.

View(Context context, @Nullable AttributeSet attrs)

: XML에서 View를 확장할 때 호출되는 생성자입니다. XML파일에서 View를 구성할 때 호출됩니다. 이 생성자에서는 attrs의 값은 버전의 기본 스타일 0을 사용하여 속성값은 Context의 테마에 지정된 AttributeSet에 있는 값입니다.

View(Context context, @Nullable AttributeSet attrs, int defStyleAttr)

: XML에서 인플레이션을 수행하고 테마 속성에서 클래스별 기본 스타일을 적용합니다.
해당 View 생성자에서는 하위 클래스가 팽창할 때 자체 기본 스타일을 사용할 수 있도록 합니다. 예를 들어 Button 클래스의 생성자는 슈퍼 클래스 생성자의 버전을 호출하고 defStyleAttr에 대해 R.attr.buttonStyle을 제공합니다. 그렇기에 테마의 버튼 스타일이 모든 기본 View 속성(특히 배경)과 Button 클래스의 속성을 수정할 수 있습니다.

View(Context context, @Nullable AttributeSet attrs,int defStyleAttr, int defStyleRes)

: XML에서 인플레이션을 수행하고 테마 속성 또는 스타일 리소스에서 클래스별 기본 스타일을 적용합니다. 이 View 생성자는 하위 클래스가 팽창할 때 자체 기본 스타일을 사용할 수 있도록 합니다.

View의 생명주기 3가지

  1. Attachment / Detachment

  2. Traversals

  3. State Save / Restore

Attachment / Detachment

View가 화면에 연결될 때 호출됩니다. 이 단계에서는 적절한 작업을 수행하기 위해 콜백을 수신하는 몇 가지 메서드가 있습니다.

onAttachedToWindow()

View가 화면에 연결될 때 호출됩니다. View가 활성화 될 수 있고 그리기 위한 표면이있다는 것을 아는 단계 입니다. 따라서 리소스 할당을 시작하거나 리스너를 설정할 수 있습니다.

onDetachedFromWindow()

View가 화면에서 분리될 때 호출됩니다. 이 시점에서는 더 이상 표면 작업을 수행하지않습니다. 예약된 작업을 중단하거나 할당된 리소스를 정리해야 하는 곳입니다. 이 메소드는 ViewGroup에서 View를 제거를 호출하거나 Activity가 파괴될 때 호출됩니다.

onFinishInflate()

이 메서드는 모든 자식들이 추가된 후에 호출됩니다.

Traversals(순회)

View 계층이 부모 노드(ViewGroup)에서 리프 노드(Child Views)로 분기되는 트리 구조와 같기 때문에 이것을 순회 단계라고 합니다. 따라서 각 메서드는 부모에서 시작하여 제약 조건을 정의하기 위해 마지막 노드까지 순회합니다.

Measure 단계와 Layout 단계는 항상 같이 발생하며. 위의 이미지와 같이 순차적으로 진행 합니다.

onMeasure()

View가 얼마나 커야 하는지 알아내기 위해 호출됩니다. ViewGroup의 경우 각 하위 보기에 대해 측정을 호출하고 결과가 자체 크기를 결정하는데 도움이 될 수 있습니다.

onMeasure(intwidthMeasureSpec, int heightMeasureSpec)

@param widthMeasureSpec Horizontal space requirements as imposed by the parent

@param heightMeasureSpec Vertical space requirements as imposed by the parent

onMeasure()는 값을 반환하지 않는 대신 setMeasuredDimension()을 호출하여 너비와 높이를 명시적으로 설정합니다.

onLayout()

화면에 View를 배치하기 위해 View를 측정한 후 호출됩니다.

onDraw()

크기와 위치는 이전 단계에서 계산되므로 이를 기반으로 보기가 스스로 그릴 수 있습니다. onDraw()에서 생성된 Canvas 객체에는 GPU로 보낼 openGL-ES명령(displayList)목록이 있습니다. 여러 번 호출되기 때문에 onDraw()에서는 객체를 생성하면 안됩니다

invalidate()

변경 사항을 표시하려는 특정 View를 강제로 다시 그리는 메서드 입니다.

requestLayout()

어떤 시점에서 View의 경계가 변경되었다면 View를 다시 측정하기 위해 requestLayout()을 호출하여 Measure 및 Layout 단계를 다시 거칠 수 있다.

onRestoreInstanceState(Parcelable state)

여기서는 이 onRestoreInstanceState메서드를 재정의하고 Parcelable에서 데이터를 읽은 다음 Parcelable에서 사용 가능한 데이터를 기반으로 로직을 작성해야 한다.

@Override
public Parcelable onSaveInstanceState() {
    Bundle bundle = new Bundle();
    // The vars you want to save - in this instance a string and a boolean
    String someString = "something";
    boolean someBoolean = true;
    State state = new State(super.onSaveInstanceState(), someString, someBoolean);
    bundle.putParcelable(State.STATE, state);
    return bundle;
}

@Override
public void onRestoreInstanceState(Parcelable state) {
    if (state instanceof Bundle) {
        Bundle bundle = (Bundle) state;
        State customViewState = (State) bundle.getParcelable(State.STATE);
        // The vars you saved - do whatever you want with them
        String someString = customViewState.getText();
        boolean someBoolean = customViewState.isSomethingShowing());
        super.onRestoreInstanceState(customViewState.getSuperState());
        return;
    }
    // Stops a bug with the wrong state being passed to the super
    super.onRestoreInstanceState(BaseSavedState.EMPTY_STATE); 
}

protected static class State extends BaseSavedState {
    protected static final String STATE = "YourCustomView.STATE";

    private final String someText;
    private final boolean somethingShowing;

    public State(Parcelable superState, String someText, boolean somethingShowing) {
        super(superState);
        this.someText = someText;
        this.somethingShowing = somethingShowing;
    }

    public String getText(){
        return this.someText;
    }

    public boolean isSomethingShowing(){
        return this.somethingShowing;
    }
}

Reference

The Life Cycle of a View in Android

profile
Android 개발 잘하고 싶어요!!!

0개의 댓글