JLOG

[안드로이드 스튜디오 강좌 #18] 레이아웃 인플레이션 이해하기 본문

안드로이드 스튜디오/Do it 안드로이드 스튜디오

[안드로이드 스튜디오 강좌 #18] 레이아웃 인플레이션 이해하기

정정선선 2020. 5. 26. 07:49

! 목표

XML 레이아웃의 내용이 메모리에 객체화 되는 과정인 '인플레이션(inflation)'을 알아보자

 

어플을 구성하려면, XML 레이아웃만 있다고 해서 화면을 띄우고 앱을 실행할 수 없다.

하나의 화면에 대해 화면을 어떻게 보여줄지 결정해주는 XML 레이아웃과 화면의 기능을 담당하는 소스 코드 파일이 필요하다.

 

 

MainActivity.java

public class MainActivity extends AppCompatActivity {
		@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//...생략
}

-super.onCreate(savedInstanceState) : 부모 클래스의 동일한 메서드를 호출

-setContentView() : XML 레이아웃 파일과 소스 코드 파일을 연결함

R.layout.(레이아웃파일명)과 같이 확장자 없이 지정해야 한다.

R은 프로젝트 창에 보이는 res 폴더를 의미한다.

layout은 res 폴더의 layout 폴더를 의미한다.

즉, R.layout.activity_main은 res/layout/activity_main.xml 파일을 의미한다.

 

 

 

1. 인플레이션(Inflation)

앱이 실행 될 때 XML 레이아웃의 내용이 메모리에 객체화되고 객체화된 XML 레이아웃을 소스파일에서 사용한다. 이렇게 XML 레이아웃의 내용이 메모리에 객체화 되는 과정을 '인플레이션(inflation)'이라고 한다.

 

XML 레이아웃은 앱이 실행되는 시점에 메모리에 객체화 된다. 반드시 setContentView로 XML 레이아웃을 메모리에 객체회 시킨 후에 뷰 객체를 참조해야만 한다.

(그렇지 않다면 앱이 중지되며 'Caused by:java.lang.NullPointerException: Attempt to invoke virtual method' 오류메세지가 뜬다.)

 

setContentView() 메서드는 activity_main.xml을 객체화하기 위해 사용했지만, 화면에 나타낼 뷰를 지정하기 위해서도 사용된다.

 

하지만 setContentView() 메서드로는 액티비티의 화면 전체(메인 레이아웃)를 설정하는 역할만 하기 때문에 부분 화면(부분 액티비티)을 메모리에 객체화할 수 없다. 부분 화면을 보여주기 위해 인플레이터를 사용해야한다. getSystemService()메서드의 LayoutInflater 클래스를 사용하면 된다.

getSystemService(Context.LAYOUT_INFLATER_SERVICE)

 

 

*참고*

부분화면이란?

화면의 일부분을 차지하는 것을 부분화면이라고 부를 수 있는데 전체 화면이 아닌 부분 화면도 별도의 XML 레이아웃 파일에 정의한 후 불러와 보여줄 수 있다.

정리하면, 메인 레이아웃에 부분 레이아웃이 포함되어 있다면 메인 레이아웃은 setContent(R.layut.activity_main)으로 객체화해 화면에 나타낸다. 분리한 부분 화면(button.xml)은 LayoutInflater 객체를 사용해 뷰그룹 객체로 객체화(인플레이션)한 후 메인 레이아웃에 추가해야 한다.

 

 

 

 

-실습

새 SampleLayoutInflater 프로젝트를 생성하자

왼쪽 프로젝트 창에서 app-오른쪽 클릭-New-Activity-Empty Activity를 선택한다.

 

Activity Name에 MenuActivity를 입력하고 Finish 버튼을 누르면,

res/layout 폴더에 새로운 XML 파일과 app/java 폴더에 새로운 java 소스 코드 파일이 생긴 것을 확인할 수 있다.

처음에 말했듯이, 하나의 화면을 띄우려면 XML 레이아웃 파일 하나와 자바 소스 코드 파일이 쌍으로 만들어져야 한다는 것을 확인할 수 있다.

 

 

activity_menu.xml를 열고 아래 코드를 작성하거나, 코드를 보고 화면을 구성해보자.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MenuActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="버튼을 눌러 부분 화면을 추가하세요"
        android:textSize="20sp" />

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="추가하기" />

    <LinearLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"/>
</LinearLayout>

parent layout 안에 있는 LinearLayout에 부분 화면이 들어갈 것이다.

 

버튼을 클릭했을 때 새로운 XML 레이아웃을 메모리에 객체화해 안쪽의 리니어 레이아웃에 나타나도록 만들어보자

왼쪽 프로젝트 창에서 /app/res/layout 폴더에서 마우스 오른쪽 클릭-New-Layout resource file을 선택한다.

File name에 sub1.xml

Root element: LinearLayout을 입력한 후 OK 버튼을 눌러준다.

생성된 sub1.xml을 열고 아래 코드를 입력하거나, 코드를 보고 화면을 구성해보자.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="부분 화면 1"
        android:textSize="30sp" />

    <CheckBox
        android:id="@+id/checkBox"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="동의합니다"
        android:textSize="25sp" />
</LinearLayout>

sub1.xml은 전체 레이아웃의 추가하기 버튼을 클릭해 넣어주기 위한 부분 레이아웃이다.

 

 

이제 소스 코드를 입력해 전체 레이아웃에 부분 레이아웃을 추가해보자.

activity_menu.xml의 짝인 MenuActivity.java 파일을 아래와 같이 수정하자.

package org.techtowm.samplelayoutinflater;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.LinearLayout;

public class MenuActivity extends AppCompatActivity {
    LinearLayout container;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_menu);

        container = findViewById(R.id.container);

        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                LayoutInflater inflater = (LayoutInflater)
                                    getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                inflater.inflate(R.layout.sub1, container, true);
                CheckBox checkBox = container.findViewById(R.id.checkBox);
                checkBox.setText("로딩되었어요.");
            }
        });

    }
}

 

 

코드설명

 container = findViewById(R.id.container);

activity_menu.xml에 있는 LinearLayout을 부분레이아웃을 담을 container로 호출 해준다.

 

 

Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                LayoutInflater inflater = (LayoutInflater)
                                    getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                inflater.inflate(R.layout.sub1, container, true);
                CheckBox checkBox = container.findViewById(R.id.checkBox);
                checkBox.setText("로딩되었어요.");
            }
        });

누르면 부분 레이아웃을 추가하기 위해 button을 호출해준다.

 

Onclick 메소드 안에는

부분 레이아웃을 설정하기 위해 getSystemService() 메서드에서 LayoutInflater 클래스를 사용해서 inflater를 선언해준다.

inflate는 첫번째 파라미터로 XML 레이아웃 리소스를, 두번째 파라미터로 부모 컨테이너를 지정한다.

View inflate (int resource, ViewGroup root)

inflater를 이용해 sub1.xml 파일을 container 객체에 설정해준다.

이제 sub1.xml 파일에 정의된 뷰들이 메모리에 로딩되었음으로 findViewById를 이용해 객체를 참조할 수 있다. 하지만 container 객체에 설정이 되었음으로, container.findViewById 형식으로 참조해야한다.

 

 

 

 

이제 앱이 실행되었을 때 MainActiviy화면이 아니라 MenuActivity 화면이 나타나도록 Manifest.xml 파일을 수정해야한다.

/app/manifests 폴더에 AndroidManifest.xml 파일을 열어 <activity> 태그 안에 android:name 속성 값을 아래와 같이 수정한다.

// 중략...
<activity android:name=".MenuActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".MainActivity"></activity>
// 중략...

 

 

 

 

실행시켜서 확인해보면 다음과 같은 화면을 확인할 수 있다.

왼쪽은 sub1.xml을 로딩하기 전이고 오른쪽은 인플레이션을 통해 부분 레이아웃(sub1.xml)을 로딩한 후의 화면이다.

 

 

XML 레이아웃으로 화면을 만드는 것이 일반적이다. 코드에서 직접 new Button(this)와 같이 코드를 부모 컨테이너에 추가할 수 있지만 코드에서 직접 추가하면 소스 코드의 양이 많아지고 복잡해져 되도록이면 XML 레이아웃을 사용하는 것이 좋다.

 

 

 

 

## 이 글은 Do it 안드로이드 앱 프로그래밍을 참고해서 작성되었습니다.

도서에는 더 자세하고 알기 쉽게 설명이 되어 있어 도서를 참고하면서 공부하는 것을 추천드립니다.

도서 정보 : http://www.yes24.com/Product/Goods/15789466

 

Do it! 안드로이드 앱 프로그래밍

안드로이드 분야 1위 도서, 개정 2판으로 돌아오다! (롤리팝, 안드로이드 스튜디오)안드로이드 분야에서 큰 사랑을 받아온 [Do it! 안드로이드 앱 프로그래밍]의 두 번째 전면 개정판이 나왔다. 최신 롤리팝 버전을 적용한 이번 개정 2판은 지난 젤리빈 개정판보다 더 개정폭이 커졌다. 특히 2014년 12월 발표된 안드로이드 공식 개발 도구인 ‘안드...

www.yes24.com

유투브 강의 : https://www.youtube.com/watch?v=nN4xnEcnjE8

 

Comments