상세 컨텐츠

본문 제목

Android View inflate 과정

카테고리 없음

by 개발혱 2022. 8. 17. 01:31

본문

inflate는 View를 메모리에 객체화 한다.

inflate를 사용하면 XML(레이아웃)이 작성된 메모리에 로딩되어 있던 것을 인스턴스화 하게 된다.

 

XML에 정의된 Root Layout과 Child View들의 속성을 읽어서 실제로 View를 만들게 된다.

성능 상의 문제 때문에 XML 파일은 빌드 과정에서 미리 컴파일 되어 있다.

미리 컴파일된 파일들 R.XXX 형태의 리소스 ID를 찾아서 메모리에 로드한 후에 이용을 시작하는 것이다.

 

setContentView()

- void setContentView(int layoutResID)

- void setContentView(View view)

- void setContentView(View view, ViewGroup.LayoutParams params)

 

addContentView(linearLayout, ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT))

기존에 생성된 View에 레이아웃을 겹칠 수 있는 기능을 한다.

 

view 오브젝트들과 일치하는 XML 레이아웃 파일을 설명한다. 이것은 절대 직접 사용되지 않는다. 

 

Activity.getLayoutInflater() or Context#getSystemService 기본적으로 LayoutInflater 사례를 설명하다.

val inflater: LayoutInflater = getLayoutInflater()
val inflater: LayoutInfater = context.getSystem(Context.LAYOUT_INFLATER_SERVICE)

1. LayoutInflater.from 함수 어떻게 동작하는지

특정 컨텍스트와 연결된 새 LayouInflater 인스턴스를 만든다. Applications는 표준을 검색하기위해서 거의 항상 Context.getSystemService()를 사용한다.

Params: Context - 이 LayoutInflater 뷰를 발생시키는 Context이다. 가장 중요한 것은, 이것은 기본값으로부터 제공한다.

protected LayoutInflater(Context context) {
        StrictMode.assertConfigurationContext(context, "LayoutInflater");
        mContext = context;
        initPrecompiledViews();
}

주어진 Context로부터 LayoutInflater를 얻는다.

public static LayoutInflater from(@UiContext Context context) {
        LayoutInflater LayoutInflater =
                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        if (LayoutInflater == null) {
            throw new AssertionError("LayoutInflater not found.");
        }
        return LayoutInflater;
}

지정된 xml 리소스로부터 새로운 보기 계층을 확장한다.

에러가 있다면 InflateException 예외를 던진다.

resource - 세부적인 xml

// LayoutInflater.inflate(R.layout.레이아웃_이름, container, false)

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
    final Resources res = getContext().getResources();
    if (DEBUG) {
        Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
                + Integer.toHexString(resource) + ")");
    }

    View view = tryInflatePrecompiled(resource, res, root, attachToRoot);
    if (view != null) {
        return view;
    }
    XmlResourceParser parser = res.getLayout(resource);
    try {
        return inflate(parser, root, attachToRoot);
    } finally {
        parser.close();
    }
}

2. Activity AppCompactActivity inflate 차이

- layoutinflate에서 어떻게 만들어 내는지.

frameworks/base/core/java/android/app/Activity.java

레이아웃 리소스로부터 activity content를 지정해라.

이 액티비티 content 리소스는 액티비티 최상단 뷰의 inflate된다.

public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
}

명백한 뷰의 내용물을 액티비티에 지정한다. 이 뷰는 액티비티의 뷰 계층에서 직접적으로 위치한다. 이것은 복잡한 뷰계층이 될 수 있다.

이 뷰는 액티비티의 뷰 계층에 직접적으로 놓는다. 이것은 복잡한 뷰 계층이 될 수 있다. 이 메소드를 부를 때, 상세한 뷰의 레이아웃 파라미터들은 무시된다. 이 메소드를 부를 때, 구체적인 뷰의 레이아웃 파라미터들은 무시되었다. 뷰의 너비와 높이 모두 MATCH_PARENT가 기본 설정이다. 자신의 레이아웃 파라미터들을 사용하기위해서 LayoutPrams 대신에 간절히 바란다.

public void setContentView(View view) {
    getWindow().setContentView(view);
    initWindowDecorActionBar();
}

Activity의 경우엔 LayoutInflater시킬 때, XML 리소스 아이디를 불러오고 XML를 파서시켜준다.

아래 설명을 적어봤다.

루트 뷰는 계층적으로 인플레이티드된다. 루트에서 제공되고 attachToRoot가 제공된다면, 이것은 루투이다. 달리 말하면 이것은 xml file에 inflate된 루트이다.

    public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
        synchronized (mConstructorArgs) {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");

            final Context inflaterContext = mContext;
            final AttributeSet attrs = Xml.asAttributeSet(parser);
            Context lastContext = (Context) mConstructorArgs[0];
            mConstructorArgs[0] = inflaterContext;
            View result = root;

            try {

appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatViewInflater.java

AppCompat

- 코어 Android의 모든 사용을 자동으로 "대체"하기 위해 사용됩니다.

- 2014년에 만들어진 라이브러리

AppCompatViewInflater

- AppCompat경우엔, view의 기본 태그(정규화된 클래스이름-TextView)를 inflate 시켜서 사용한다.

    @Nullable
    public final View createView(){
    ...
        // We need to 'inject' our tint aware Views in place of the standard framework versions
        switch (name) {
            case "TextView":
                view = createTextView(context, attrs);
                verifyNotNull(view, name);
                break;
            case "ImageView":
                view = createImageView(context, attrs);
                verifyNotNull(view, name);
                break;
    }           
                
                
    @NonNull
    protected AppCompatTextView createTextView(Context context, AttributeSet attrs) {
        return new AppCompatTextView(context, attrs);
    }

 

3. LayoutInflater 어떻게 커스텀 할 수 있는지.

appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatTextView.java

- AppCompatViewInflater.java 처럼 onCreateView에 태그값을 넣어서 뷰를 대체하게 만든다.

- Souce코드에서 extends하여 텍스트를 받고 오버라이드하여 속성값을 커스텀한다.

 

4. 액티비티를 뷰가 사용되는 레이아웃을 소스에서 바꿀 수 있는것 코드 상이 아닌 테마에서도 수정할 수 있다. 어떻게 동작하는건지. 

 <style name="GreenText" parent="TextAppearance.AppCompat">
    <item name="android:textColor">#00FF00</item>
</style>

//parent 속성을 사용하는 대신 점 표기법을 통해 스타일 이름을 확장하여 스타일을 상속받을 수 있다.
<style name="GreenText.Large">
    <item name="android:textSize">22dp</item>
</style>

 

참고 자료

- [안드로이드 기초] Android는 어떻게 UI를 구성할까?(1) - Inflate

- [안드로이드 기초] Android는 어떻게 UI를 구성할까?(2) - View

- Docs > LayoutInflater

- 스타일 및 테마

 

LayoutInflater  |  Android Developers

android.net.wifi.hotspot2.omadm

developer.android.com

 

Android Drawing Process 1(App surface, SF Layer)

학기가 끝나서, 지난학기간 한 것들을 포스팅하려고 한다. 언제 다 할지는 미지수지만 그래도 틈틈히 할 예정이다. Smartphone display에 대해 공부를 하다보면 필연적으로 해당 Smartphone 상 동작하는

lastyouth.tistory.com