Android

[깡쌤의 안드로이드 프로그래밍 with 코틀린][1. 안드로이드 앱 개발 준비하기] 2. 안드로이드 앱의 기본 구조

나말지 2024. 12. 25. 21:56

안드로이드는 리눅스 커널을 기반으로 구글에서 제작한 모바일 운영체제입니다. 구글은 2008년 안드로이드 1.0 버전을 출시한 이후 새버전을 계속 내놓아 전 세계 모바일 플랫폼 시장의 70~80%를 차지하고 있습니다.

 

1. 안드로이드 소개

 

안드로이드는 어떤 특징이 있을까?
  • 안드로이드는 공개 운영체제인 리눅스를 기반으로 합니다.
  • 안드로이드 앱은 자바나 코틀린 언어를 이용해 개발합니다.
  • 안드로이드 운영체제의 주요 부분과 라이브러리, 구글에서 만든 앱 등의 코드는 대부분 공개되어 있습니다.
  • 안드로이드 스마트폰은 구글뿐 아니라 여러 제조업체에서 만들 수 있습니다.
  • 안드로이드 앱은 구글의 플레이 스토어뿐만 아니라 다양한 방법으로 사용자에게 배포할 수 있습니다.
  • 안드로이드 플랫폼에서는 모든 응용 프로그램이 평등하다는 사상을 바탕으로 모바일에 기본으로 탑재된 앱과 개발자가 만든 앱이 똑같은 환경에서 똑같은 API를 이용합니다.
안드로이드 운영체제의 구조

앱 개발자가 운영체제의 구조까지 자세히 알 필요는 없지만 상식 수준에서 알아 두면 좋습니다. 

  • 리눅스 커널(Linux Kernel)
    • 안드로이드는 리눅스에 기반을 둔 오픈소스 소프트웨어 스택입니다.
  • 하드웨어 추상화 레이어(hardware abstraction layer, HAL)
    • 하드웨어의 추상화 계층으로, 상위의 자바 API 프레임워크에서 하드웨어 기능을 이용할 수 있게 표준 인터페이스를 제공합니다.
  • 안드로이드 런타임(Android runtime)
    • 흔히 ART라고 하며 앱을 실행하는 역할을 합니다. 안드로이드 5.0 버전에서는 Dalvik이 안드로이드 앱을 실행했지만 5.0 버전부터는 ART로 바뀌었습니다. 안드로이드 앱은 DEX 파일로 빌드되는데 이 DEX 파일을 해석해서 실행하는 주체가 바로 ART입니다.

안드로이드 소프트웨어 스택

https://developer.android.com/guide/platform?hl=ko

 

플랫폼 아키텍처  |  Platform  |  Android Developers

Android는 다양한 기기와 폼 팩터에 사용할 수 있도록 개발된 Linux 기반의 오픈소스 소프트웨어 스택입니다. 다음 다이어그램에서는 Android 플랫폼의 주요 구성요소를 보여줍니다. Android 플랫폼의

developer.android.com

 

자바에서는 개발자가 소스 코드를 작성한 후 컴파일하면 클래스 파일이 만들어집니다. 이 클래스 파일을 자바 가상 머신(Java virtual machine, JVM)에서 실행합니다. 그런데 안드로이드는 자바 클래스를 런타임 때 그대로 실행하지 않고 DEX 파일로 컴파일합니다. 그리고 DEX 파일을 해석하는 ART(Android runtime)에서 실행합니다. 물론 DEX 파일은 안드로이드 스튜디오에서 앱을 빌드할 때 자동으로 생성되므로 개발자가 직접 만들 필요는 없습니다.

  • 네이티브 C/C++ 라이브러리
    • 안드로이드 앱은 대부분 자바 프레임워크로 개발하지만 네이티브 C/C++ 라이브러리를 이용할 수도 있는데 이를 안드로이드 NDK(Native development kit)라고 합니다.
  • 자바 API 프레임워크
    • 앱을 개발할 때 사용하는 자바 API입니다. 자바 API 프레임워크에서 제공하는 기술을 이용하여 앱의 다양한 기능을 개발합니다.
앱 개발 언어

안드로이드가 처음 나왔을 때부터 오랜 기간 자바로 앱을 개발해 왔습니다. 그런데 2017년 구글 IO 행사에서 코틀린을 안드로이드 공식 언어로 지정하면서 이제 안드로이드 개발 언어로는 자바와 코틀린 두 가지를 사용합니다.

 

안드로이드 버전에 관하여

안드로이드 버전은 10.0, 11.0 처럼 운영체제 버전을 가리키지만 앱을 개발할 때 사용하는 버전은 API 레벨(SDK 버전)입니다. 운영체제 버전별로 API 레벨이 지정돼 있어서 소스 코드에서는 대부분 API 레벨을 이용합니다. 따라서 개발자는 운영체제 버전과 API 레벨을 함께 알고 있어야 합니다.

 

코드명은 안드로이드 버전의 별칭으로 사용하는데, 예를 들어 안드로이드 9.0 버전을 Pie라는 코드명으로 부릅니다. 그런데 구글에서는 안드로이드 10.0 버전부터 코드명을 사용하지 않겠다고 선언했습니다. 안드로이드 7.x 처럼 버전에 'x' 자가 붙은 것은 하위 버전이 있다는 의미입니다.

 

버전 코드명 API 레벨 출시 연도
Android 1.0 - 1 2008
Android 1.1 Petit Four 2 2009
Android 1.5 Cupcake 3 2009
Android 1.6 Donut 4 2009
Android 2.0.x ~ 2.1 Eclair 5~7 2009
Android 2.2.x Froyo 8 2010
Android 2.3.x Gingerbread 9~10 2010
Android 3.x Honeycomb 11~13 2011
Android 4.0.x Ice Cream Sandwich 14~15 2011
Android 4.1.x ~ 4.3.x Jelly Bean 16~18 2012
Android 4.4.x Kitkat 19~20 2013
Android 5.x Lollipop 21~22 2014
Android 6.x Marshmallow 23 2015
Android 7.x Nougat 24~25 2016
Android 8.x Oreo 26~27 2017
Android 9.0 Pie 28 2018
Android 10.x - 29 2019
Android 11.0 - 30 2020

 

2. 안드로이드 앱 개발의 특징

 

안드로이드 앱 개발의 핵심은 컴포넌트(component)입니다. 안드로이드 앱 개발과 관련된 무서를 읽다 보면 '액티비티 컴포넌트', '서비스 컴포넌트' 등 컴포넌트라는 용어가 자주 등장합니다. 안드로이드 앱 개발의 구조를 이해하려면 컴포넌트가 무엇이고 어떻게 동작하는지 반드시 알아야 합니다. 

 

컴포넌트는 애플리케이션의 구성 요소다.

컴포넌트는 안드로이드 앱뿐만 아니라 여러 애플리케이션을 개발할 때 사용하는 개념입니다. 컴포넌트를 한마디로 정의하면 애플리케이션의 구성 요소라고 할 수 있습니다.

 

컴포넌트는 애플리케이션이 아니라 애플리케이션을 구성하는 단위입니다. 즉, 하나의 애플리케이션은 여러 컴포넌트로 구성됩니다.컴포넌트가 어떤 형태인지는 상황에 따라 달라지는데 JAR 파일이나 DLL로도 개발합니다. 

 

안드로이드 앱의 기본 구조도 컴포넌트에 기반을 두므로 하나의 앱은 여러 컴포넌트로 구서오딥니다. 그리고 안드로이드에서는 클래스로 컴포넌트를 개발합니다. 즉, 하나의 클래스가 하나의 컴포넌트가 되는 거죠.

안드로이드 앱을 구성하는 클래스는 모두 컴포넌트인가?

안드로이드에서는 클래스로 컴포넌트를 개발한다고 했지만 애플리케이션을 구성하는 모든 클래스가 컴포넌트라는 이야기는 아닙니다. 앱은 여러 클래스로 구성되는데 크게 컴포넌트 클래스와 일반 클래스로 구분합니다. 앱이 실행될 때 클래스의 객체 생성부터 소멸까지 생명주기 관리를 개발자 코드에서 한다면 일반 클래스입니다. 즉, 안드로이드 앱의 구성 요소인 컴포넌트가 아닌 개발자가 임의의 목적으로 만든 클래스인 거죠. 그런데 개발자가 만들기는 했지만 생명주기를 안드로이드 시스템에서 관리한다면 컴포넌트 클래스입니다.

안드로이드 컴포넌트는 4종류다

컴포넌트는 액티비티, 서비스, 콘텐츠 프로바이더, 브로드캐스트 리시버 이렇게 4가지로 구분됩니다. 컴포넌트는 앱이 실행될 때 각각 다른 기능을 합니다.

 

  • 액티비티
    • 화면을 구성하는 컴포넌트입니다. 앱의 화면을 안드로이드폰에 출력하려면 액티비티를 만들어야 하며, 앱이 실행되면 액티비티에서 출력한 내용이 안드로이드폰에 나옵니다.
  • 서비스
    • 백그라운드 작업을 하는 컴포넌트입니다. 화면 출력 기능이 없으므로 서비스가 실행되더라도 화면에는 출력되지 않습니다. 서비스 컴포넌트는 화면과 상관없이 백그라운드에서 장시간 실행해야 할 업무를 담당합니다.
  • 콘텐츠 프로바이더
    • 앱의 데이터를 공유하는 컴포넌트입니다. 안드로이드폰에는 많은 앱이 설치되어 있으며 앱 간에 데이터를 공유할 수도 있습니다. 하나의 앱이 자신의 데이터를 다른 앱에 공유하려면 콘텐츠 프로바이더를 만들어야 하며, 다른 앱에서는 그 콘텐츠 프로바이더를 이용해 데이터에 접근합니다. 예를 들어 카카오톡 앱에서 프로필을 변경할 때 갤러리 앱의 사진을 이용할 수 있습니다. 이때 콘텐츠 프로바이더를 이용해 데이터를 주고 받습니다.
  • 브로드캐스트 리시버
    • 시스템 이벤트가 발생할 때 실행되게 하는 컴포넌트 입니다. 여기서 이벤트는 화면에서 발생하는 사용자 이벤트가 아니라 시스템에서 발생하는 특정 상황을 의미합니다. 예를 들어 부팅 완료, 배터리 방전 같은 상황을 말합니다.
4가지 컴포넌트를 어떻게 구분하는가?

4가지 컴포넌트를 구분하는 건 쉽습니다. 컴포넌트는 앱이 실행될 때 안드로이드 시스템에서 생명주기를 관리하는 클래스지만 개발자가 만들어야 하는 클래스입니다. 개발자가 컴포넌트 클래스를 만들 때는 지정된 클래스를 상속받아야 하는데 이 상위 클래스를 보고 구분할 수 있습니다. 액티비티는 Activity 클래스를 상속받아 만듭니다. 서비스는 Service, 콘텐츠 프로바이더는 ContentProvider, 브로드캐스트 리시버는 BroadcastReceiver 클래스를 상속받아서 만듭니다.

컴포넌트는 앱 안에서 독립된 실행 단위다

컴포넌트는 애플리케이션 안에서 독립된 실행 단위라는 중요한 특징이 있습니다. 독립된 실행 단위란 컴포넌트끼리 서로 종속되지 않아서 코드 결합이 발생하지 않는다는 의미입니다. 카카오톡의 목록 화면과 채팅 화면을 예로 들어 설명해보겠습니다.

 

채팅방 목록 화면을 ListActivity 라는 클래스 명으로, 채팅 화면을 ChatActivity 라는 클래스명으로 작성했고 ListActivity 에서 ChatActivity를 실행해 화면 전환을 한다고 가정해 봅시다.

ListActivity에서 ChatActivity를 실행해야 하므로 쉽게 생각하면 ListActivity에서 ChatActivity의 객체를 생성해 실행하면 될 것 같습니다. 두 클래스를 결합해서 실행하는 방법이죠. 그런데 안드로이드에서는 이 방법은 불가능합니다. 컴포넌트의 생명주기를 안드로이드 시스템에서 관리하므로 코드에서 직접 객체를 생성해 실행할 수 없기 때문입니다.

 

그럼 어떻게 해야 할까요? ListActivity에서 ChatActivity를 실행해야 한다면 안드로이드 시스템에 의뢰해서 시스템이 ChatActivity를 실행해야 합니다. 즉, ListActivity와 ChatAcitivity를 코드로 결합해서 직접 실행하는 것이 아니라 안드로이드 시스템에 의뢰함으로써 두 클래스가 서로 종속되지 않고 독립해서 실행되게 해야 합니다.

 

앱 실행 시점이 다양하다

컴포넌트가 앱 내에서 독립해서 실행되는 특징 덕분에 앱의 실행 시점이 다양할 수 있습니다. 일반적으로 앱을 설치하면 홈 화면에 아이콘이 나오고 그 아이콘을 사용자가 터치해서 실행합니다.

 

앱의 첫 화면이 ListActivity라고 가정하면 ListActivity부터 실행되어 목록 화면이 나옵니다. 하지만 앱은 사용자가 직접 실행하지 않아도 얼마든지 실행될 수 있습니다. 예를 들어 사용자가 알림 창에서 메시지 수신 알림을 터치하면 바로 채팅 화면이 열립니다. 즉, ListActivity부터 앱이 실행되지 않고 바로 ChatActivity가 실행되는 구조입니다. 이처럼 앱의 실행 시점은 다양할 수 있습니다. 그래서 안드로이드 앱에는 메인 함수 개념이 없다고 말합니다. 메인 함수란 앱의 단일 시작점을 의미하는데 안드로이드 앱은 실행 시점이 다양해서 메인 함수 개념이 없다고 표현하는 것이죠.

애플리케이션 라이브러리를 사용할 수 있다

애플리케이션 라이브러리란 다른 애플리케이션을 라이브러리처럼 이용하는 것을 말합니다.

 

카카오톡을 예로 들면, 채팅 화면에서 카메라 앱을 실행해 사진을 찍은 뒤 이 사진 데이터를 반환받아 다시 채팅화면에 출력할 수 있습니다. 이때 카카오톡 앱에서 카메라 앱을 이용해 사진을 찍었으므로 카메라 앱이 카메라 앱을 라이브러리처럼 이용한 것입니다.

 

이처럼 안드로이드 앱은 사용자가 실행하지 않아도 실행될 수 있고 실행 지점도 다양해서 다른 앱과 연동할 수 있습니다.

리소스를 활용한 개발

안드로이드 앱 개발의 또 다른 특징은 리소스를 많이 활용한다는 점입니다. 리소스란 코드에서 정적인 값을 분리한 것입니다. 앱에서 발생하는 데이터나 사용자 이벤트에 따른 동적인 값이 아니라 항상 똑같은 값이라면 굳이 코드에 담지 않고 분리해서 개발하는 것이죠. 이렇게 하면 코드가 짧아져서 개발 생산성과 유지보수성이 좋아집니다.

 

3. 앱 구성 파일 분석

 

안드로이드 프로젝트를 만들면 자동으로 완성되는 "Hello World!" 문자열 출력 앱을 살펴보면서 앱을 구성하는 파일과 코드를 분석해 보겠습니다.

프로젝트의 폴더 구성 알아보기

안드로이드 앱 프로젝트를 만들면 많은 폴더와 파일이 생성됩니다. 하지만 대부분은 빌드 도구와 관련된 것이며 개발자가 관심을 둬야 할 파일은 프로젝트 폴더에서 [모듈명 > src > main] 안에 있습니다. 그런데 안드로이드 스튜디오의 프로젝트 탐색창을 윈도우 파일 탐색기처럼 모든 폴더와 파일을 보여 주지 않습니다. 개발자가 분석하거나 작성해야 하는 폴더와 파일만 보여 줍니다.

안드로이드 스튜디오의 탐색 창에서 본 폴더 구조

 

프로젝트를 만들면 app이라는 모듈이 자동으로 생성됩니다. 모듈 하나가 앱 하나이며 프로젝트는 여러 모듈을 묶어서 관리하는 개념입니다. 하나의 프로젝트에는 자동으로 만들어지는 app 모듈 이외에 여러 모듈을 추가할 수 있습니다. 모듈은 앱 단위이므로 새로운 모듈을 추가한다는 것은 새로운 앱을 개발한다는 것과 같습니다.

(일반적으로 하나의 모듈은 하나의 앱을 의미하지만 원한다면 하나의 앱을 여러 모듈로 나누어 개발할 수도 있습니다.)

모듈의 폴더 구성 알아보기

모듈은 어떤 폴더와 파일로 구성되는지 알아보겠습니다.

이름 설명
build.gradle 빌드 설정 파일
AndroidManifest.xml 앱의 메인 환경 파일
res 리소스 폴더
activity_main.xml 레이아웃 XML 파일
MainActivity.kt 메인 액티비티 파일

 

  • 그레들 빌드 설정 파일

그래들(Gradle)은 안드로이드 앱의 빌드 도구입니다. 그래들의 설정 파일이 바로 build.gradle 이며 앱을 빌드하는 데 필요한 설정을 이 파일에 등록합니다. 그런데 탐색창을 보면 build.gradle 파일이 2개 있습니다.

 

 

하나는 프로젝트 수준의 build.gradle(Project: MyFirstApplication)이고, 또 하나는 모듈 수준의 build.gradle(Module:app)입니다. 모듈은 앱을 의미하므로 대부분의 빌드 설정은 모듈 수준의 그레이들 파일에 작성합니다.

 

모듈 수준의 그래들 파일을 열어 보면 몇 가지 설정이 자동으로 등록돼 있습니다. 이 값을 수정하거나 새로 추가하면서 빌드 환경을 설정합니다.

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.android)
    alias(libs.plugins.kotlin.compose)
}

android {
    namespace = "com.example.myfirstapplication"
    // 안드로이드 SDK 34 버전을 적용해서 컴파일하라는 의미
    compileSdk = 34

    defaultConfig {
    	// 앱의 식별자이므로 고유한 문자열이어야 함
        applicationId = "com.example.myfirstapplication"
        // 앱을 설치할 수 있는 기기의 최소 SDK 버전을 의미하며 그 이하 버전의 기기에는 설치되지 않음
        minSdk = 24
        // 개발할 때 적용되는 SDK 버전으로 30으로 지정하면 30버전의 SDK로 개발한다는 의미
        targetSdk = 34
        // 앱의 버전을 명시, 초깃값은 1이지만 앱이 사용자의 스마트폰에 설치되어 이용되다가 업데이트 될 때 이 버전을 올려 다시 배포
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
    	// 개발 언어의 버전을 설정, 참고로 자바 버전 선언을 생략하면 기본적으로 1.6이 적용됨
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    kotlinOptions {
        jvmTarget = "11"
    }
    buildFeatures {
        compose = true
    }
}

dependencies {
    // 앱에서 이용하는 라이브러리의 버전을 설정
    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.lifecycle.runtime.ktx)
    implementation(libs.androidx.activity.compose)
    implementation(platform(libs.androidx.compose.bom))
    implementation(libs.androidx.ui)
    implementation(libs.androidx.ui.graphics)
    implementation(libs.androidx.ui.tooling.preview)
    implementation(libs.androidx.material3)
    testImplementation(libs.junit)
    androidTestImplementation(libs.androidx.junit)
    androidTestImplementation(libs.androidx.espresso.core)
    androidTestImplementation(platform(libs.androidx.compose.bom))
    androidTestImplementation(libs.androidx.ui.test.junit4)
    debugImplementation(libs.androidx.ui.tooling)
    debugImplementation(libs.androidx.ui.test.manifest)
}

 

  • 메인 환경 파일

개발을 진행하면서 메니페스트 파일을 분석하고 수정하는 일이 많은데 안드로이드 시스템은 이 파일에 설정한 대로 사용자의 폰에서 앱을 실행합니다. 즉, 매니페스트 파일은 개발부터 실행까지 중요한 역할을 합니다.

<?xml version="1.0" encoding="utf-8"?>
<!-- 매니페스트 파일의 루트 태그입니다. xmlns는 XML의 네임스페이스 선언이며 URL이 http://schemas.android.com/apk/res/android 로 선언되었다면 안드로이드 표준 네임스페이스입니다. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <!-- 앱 전체를 대상으로 하는 설정입니다. -->
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        
        <!-- res/mipmap/ic_launcher.png 파일을 의미합니다. XML 속성값이 @로 시작하면 리소스를 의미합니다. -->
        android:icon="@mipmap/ic_launcher"
        
        <!-- res/values/strings.xml 파일에 app_name 으로 등록된 문자열 리소스를 가리킵니다. -->
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        
        <!-- theme 설정은 앱에 적용해야 하는 테마를 설정하는 것으로 res/values/themes.xml 파일에 Theme.AndroidLab 이름으로 선언한 테마를 적용하겠다는 의미입니다. -->
        android:theme="@style/Theme.MyFirstApplication"
        tools:targetApi="31">
        
        <!-- 안드로이드 컴포넌트는 시스템에서 생명주기를 관리합니다. 그리고 시스템은 매니페스트 파일에 있는 대로 앱을 실행합니다. 결국 컴포넌트는 매니페스트 파일에 등록해야 시스템이 인지합니다. -->
        <!-- 액티비티는 activity 태그로, 서비스는 service 태그로, 브로드캐스트 리시버는 receiver 태그로, 그리고 콘텐츠 프로바이더는 provider 태그로 등록합니다. -->
        <!-- 컴포넌트 하나당 태그 하나로 등록하며 만약 액티비티가 10개라면 activity 태그를 10개 선언해야 합니다. -->
        <activity
            <!-- name 속성은 필수이며 .MainActivity 로 설정했다면 MainActivity 클래스를 액티비티로 등록하겠다는 의미입니다. -->
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.MyFirstApplication">
            
            <!-- 안에 있는 action 태그의 name 값이 android.intent.action.MAIN 문자열로 -->
            <!-- category 태그의 name 값이 android.intent.category.LAUNCHER로 선언되며 이 액티비티는 앱 아이콘을 클릭했을 때 실행되는 액티비티라는 의미입니다. -->
            <!-- 앱이 설치되면 홈 화면에 앱 아이콘이 나오는데, 이 아이콘을 터치했을 때 실행되어야 하는 액티비티라는 의미입니다. -->
            <!-- 이 태그는 생략가능하지만 생략하게 되면 앱을 설치해도 홈 화면에 앱 아이콘이 나오지 않아 사용자가 앱을 직접 실행할 수 없게 됩니다. -->
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

  • 리소스 폴더

res 폴더는 앱의 리소스를 등록하는 목적으로 사용합니다. 모듈이 만들어지면 res 폴더 아래에 다음과 같은 폴더가 기본으로 생깁니다.

  • drawable : 이미지 리소스
  • mipmap: 앱 아이콘 이미지
  • values: 문자열 등의 값으로 이용되는 리소스

res 폴더 아래에 리소스를 만들면 자동으로 R.java 파일에 상수 변수로 리소스가 등록되며 코드에서는 이 상수 변수로 리소스를 이용합니다. R.java는 개발자가 만드는 파일이 아니며 res 폴더에 있는 리소스를 보고 자동으로 만들어집니다.

 

만약 개발자가 res/drawable 폴더에 person1,.png 파일과 send.png 파일을 만들었다면 이 리소스를 식별하기 위한 int형 변수가 R.java 파일에 등록됩니다. 그리고 코드에서 이 리소스 파일을 이용하려면 R.drawable.person1R.drawable.send로 식별합니다. R.java 파일에 각 폴더의 하위 클래스가 만들어지고 그 안에 파일명을 기준으로 int 형 변수가 자동으로 만들어집니다. 따라서 res/drawable/send.png 파일이라면 R.drawable.send 라고 이용합니다.

 

이처럼 안드로이드 리소스 파일이 R.java 파일에 상수 변수로 등록되어 이용되면서 아래와 같은 규칙이 생깁니다.

  • res 하위의 폴더명은 지정된 폴더명을 사용해야 합니다.
  • 각 리소스 폴더에 다시 하위 폴더를 정의할 수는 없습니다.
  • 리소스 파일명은 자바의 이름 규칙을 위배할 수 없습니다.
  • 리소스 파일명에는 알파벳 대문자를 이용할 수 없습니다.

이런 식으로 리소스가 등록되면 R.java 파일에 int 형 변수가 생기므로 res 폴더에는 개발자 임의의 폴더를 사용할 수 없습니다. 지정된 폴더명을 사용해야 한다는 의미입니다. 즉, 이미지는 drawable 폴더를 이용해야 하며 각 리소스 폴더에 하위 폴더를 만들 수 없습니다.

  • 메인 액티비티 파일

매니페스트 파일의 설정값에 따라 폰에 앱을 설치한 후 앱 아이콘을 터치하면 MainActivity.kt 파일이 실행됩니다.

package com.example.myfirstapplication

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.myfirstapplication.ui.theme.MyFirstApplicationTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            MyFirstApplicationTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Greeting(
                        name = "Android",
                        modifier = Modifier.padding(innerPadding)
                    )
                }
            }
        }
    }
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(
        text = "Hello $name!",
        modifier = modifier
    )
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    MyFirstApplicationTheme {
        Greeting("Android")
    }
}

 

파일 내용을 간략하게 살펴보면 ComponentActivity 를 상속받아 MainActivity라는 클래스를 정의했습니다. ComponentActivity는

public class ComponentActivity extends androidx.core.app.ComponentActivity

 

androidx.core.app.ComponentActivity를 상속 받았고 다시 이 클래스는 Activity 클래스를 상속받았습니다.

public class ComponentActivity extends Activity

 

결국 ComponentActivity 는 Activity의 하위 클래스입니다. 따라서 MainActivity는 액티비티 컴포넌트 클래스입니다. 즉, 이 클래스는 화면 출력을 목적으로 하는 액티비티 클래스라는 의미입니다.

MainActivity 클래스가 실행되면 onCreate() 함수가 자동으로 호출되며 onCreate() 함수 안의 구문을 실행합니다.