본문으로 건너뛰기
AIDevOps
  • Learn
  • Learning Paths
  • Practice
  • Open Source
  • Books
  • Engineering

    AI DevOpsAI 서비스 개발·운영 전체 지도LLMOpsLLM 배포·평가·관측실전 프로젝트AI Agent 프로젝트 실습

    Knowledge

    Docs기술 문서 모음Blog엔지니어링 아티클Plogger개발 기록 피드

    Validate

    Certification3단계 역량 인증 · 준비 중
AI Models
LlamaMistralGemmaDeepSeekQwen
📱 Mobile
Mobile 입문 & 로드맵KotlinAndroidFlutter
🤖 AI 실전 개발
AI 실전 입문 & 로드맵Hugging FaceLangChainLlamaIndexLLMOps|LangGraphMCPMulti-AgentAgent Evaluation
🧠 AI Core
AI 입문 & 로드맵ML FundamentalsLLM Fundamentals|Python AIC++|PyTorchTensorFlowJAX
🧠 AI Agent 개발
금융 AI AgentLLM API 서버주식 투자 AgentAIOps AI Agent교육 AI Agent코딩 AI Agent
🌱 Spring Cloud
Spring 입문 & 로드맵Spring Cloud GatewaySpring BootJava|Spring AISpring SecuritySpring BatchSpring JPA
🐳 DevOps
DevOps 입문 & 로드맵LinuxDockerCI/CD|Kubernetes 기본K8s 심화/실무PrometheusGrafana
🧱 인프라
인프라 입문 & 로드맵NginxRedis
☁️ 클라우드
클라우드 입문 & 로드맵AWSGCPAzureNCPCloudflare
🎨 Frontend
Frontend 입문 & 로드맵JavaScriptTypeScript|ReactNext.js|VueNuxt
⚙️ Backend
Backend 입문 & 로드맵Python 기본FastAPIDjangoFlask|CGoGinNode.js
💾 Database
DB 입문 & 로드맵공통 SQLOracleMySQLPostgreSQL|MongoDB벡터 DB
🧪 검증
k6JMeternGrinder
AIDevOps

Engineering AI. From Code to Production.
AI와 AI Agent를 개발하고 운영하기 위한 엔지니어링 학습 플랫폼

Learn

  • 전체 가이드
  • Learning Paths
  • Practice
  • Books

Resources

  • AI DevOps
  • LLMOps
  • 실전 프로젝트
  • Docs
  • Blog
  • Plogger
  • Open Source
  • Certification (준비 중)

Start Here

  • AI Core 로드맵
  • AI 실전 개발 로드맵
  • Spring Cloud 로드맵
  • DevOps 로드맵
  • 인프라 로드맵

 

  • 클라우드 로드맵
  • Frontend 로드맵
  • Mobile 로드맵
  • Backend 로드맵
  • Database 로드맵
© 2026 AI DevOps Korea. All rights reserved.
이용약관개인정보처리방침Sitemaptestforge.kr
  1. Home
  2. Learn
  3. Mobile
  4. Android
Kotlin 기반 Android 개발 완전 가이드

🤖 Android 완전 가이드

Visitors

처음 Android Studio를 여는 순간부터 Play 스토어에 앱을 올리는 순간까지, Kotlin과 Jetpack Compose로 안드로이드 앱을 만드는 전 과정을 하나하나 친절하게 설명합니다. 왜 이렇게 하는지 이유까지 함께 이해할 수 있도록 구성했습니다.

  • Intermediate · 중급
  • 업데이트 2026.09.05
  • 약 21분 읽기
  • 19개 섹션
  • 예제 코드 14개
🤖
모바일 앱 개발Jetpack Compose UIRetrofit 네트워크 통신MVVM 아키텍처Play 스토어 배포

관련 프레임워크 & 개발환경

🅺Kotlin→🦋Flutter→

목차

0 / 21
  1. 가이드 사용법
  2. 구조 다이어그램
  3. Android 개발이란?
  4. 개발 환경 구축
  5. 첫 프로젝트 만들기
  6. 프로젝트 구조 이해
  7. Compose 첫걸음
  8. 레이아웃 & Modifier
  9. 상태 관리
  10. 리스트 UI (LazyColumn)
  11. 화면 전환
  12. ViewModel & 생명주기
  13. 네트워크 통신
  14. 권한 처리
  15. 로컬 데이터 저장
  16. 테스트 작성하기
  17. 빌드 및 배포
  18. 다음 단계
  19. Android 설계
  20. 운영 기준
  21. 검증 전략
목차 21개 섹션
  1. 가이드 사용법
  2. 구조 다이어그램
  3. Android 개발이란?
  4. 개발 환경 구축
  5. 첫 프로젝트 만들기
  6. 프로젝트 구조 이해
  7. Compose 첫걸음
  8. 레이아웃 & Modifier
  9. 상태 관리
  10. 리스트 UI (LazyColumn)
  11. 화면 전환
  12. ViewModel & 생명주기
  13. 네트워크 통신
  14. 권한 처리
  15. 로컬 데이터 저장
  16. 테스트 작성하기
  17. 빌드 및 배포
  18. 다음 단계
  19. Android 설계
  20. 운영 기준
  21. 검증 전략

가이드 사용법

읽는 방향

Android를 실무 흐름으로 이해하기

처음 Android Studio를 여는 순간부터 Play 스토어에 앱을 올리는 순간까지, Kotlin과 Jetpack Compose로 안드로이드 앱을 만드는 전 과정을 하나하나 친절하게 설명합니다. 왜 이렇게 하는지 이유까지 함께 이해할 수 있도록 구성했습니다. 이 가이드는 개념을 나열하기보다, 실제 프로젝트에서 판단해야 하는 순서대로 내용을 따라갈 수 있게 구성했습니다.

핵심 관점

프론트엔드 / 앱 개발

화면을 그리는 법에서 멈추지 않고, 상태, 데이터 요청, 라우팅, 접근성, 배포 단위까지 함께 봅니다.

모바일 앱 개발Jetpack Compose UIRetrofit 네트워크 통신MVVM 아키텍처Play 스토어 배포

구조 다이어그램

글로 읽은 내용을 머릿속에 오래 남기려면 먼저 흐름을 그림으로 잡는 편이 좋습니다. 아래 두 그림은 Android를 학습할 때 계속 되돌아볼 수 있는 기준 지도입니다.

학습 흐름

다이어그램 렌더링 중…

아키텍처 관점

다이어그램 렌더링 중…

Android 개발이란?

Android를 처음 펼칠 때는 세부 명령보다 큰 그림이 먼저입니다. 이 섹션에서는 앞으로 배울 개념들이 어떤 문제를 풀기 위해 등장했는지부터 잡아봅니다.

Android는 전 세계 스마트폰의 70% 이상이 쓰는 Google의 모바일 운영체제입니다. 처음 시작하는 분들이 가장 먼저 궁금해하는 것은 "어떤 언어와 도구로 시작해야 하나요?"일 텐데, 결론부터 말하면 Kotlin 언어 + Jetpack Compose UI 툴킷 조합이 2024년 이후 Google이 공식적으로 권장하는 최신 표준입니다. 예전에는 Java + XML 레이아웃 조합이 표준이었지만, 지금 새로 배운다면 굳이 옛날 방식을 먼저 익힐 필요가 없습니다. 이 가이드는 처음부터 끝까지 Kotlin과 Compose만으로 진행합니다.

Compose가 낯설게 느껴질 수 있는데, 간단히 말하면 "화면에 무엇을 어떻게 그릴지"를 XML 파일 대신 Kotlin 함수로 직접 선언하는 방식입니다. React나 Flutter를 다뤄본 적이 있다면 "상태(state)가 바뀌면 화면이 자동으로 다시 그려진다"는 개념이 똑같아서 금방 익숙해질 것입니다. 처음이라도 걱정할 필요는 없습니다 — 이 가이드에서 개념 하나하나를 실제 코드와 함께 설명합니다.
비교 대상예전 방식이 가이드에서 다루는 방식
UI 작성XML 레이아웃 파일Kotlin @Composable 함수
언어JavaKotlin (더 간결하고 Null 안전)
상태 반영findViewById로 수동 갱신상태가 바뀌면 자동으로 재구성(recomposition)
공식 권장 여부유지보수 대상Google 공식 최신 표준 (2024~)

Tip

이미 Java/XML로 된 오래된 사내 프로젝트를 유지보수해야 한다면 그 프로젝트는 그 방식을 따라야 하지만, 새로 시작하는 학습이라면 Compose로 시작하는 것이 시간을 아끼는 길입니다.

개발 환경 구축

여기서는 개발 환경 구축을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

Android 개발에 필요한 것은 딱 하나, 공식 IDE인 Android Studio입니다. 이 안에 코드 편집기, Android SDK(빌드에 필요한 도구 모음), 에뮬레이터(가상 스마트폰)가 전부 포함되어 있어서 별도로 여러 프로그램을 설치할 필요가 없습니다.
BASH
# Android Studio 설치 후 최초 실행 시 "Setup Wizard"가 뜹니다.
# Standard 옵션을 선택하면 Android SDK, 빌드 도구, 에뮬레이터 이미지가
# 자동으로 다운로드됩니다. (인터넷 속도에 따라 10~20분 정도 소요)

# 설치가 끝났는지 확인하려면 상단 메뉴에서:
# Android Studio > Settings > Languages & Frameworks > Android SDK
# 여기서 최신 SDK Platform (API 34 이상)이 체크되어 있는지 확인하세요.
운영체제설치 방법참고사항
Windows공식 사이트에서 .exe 인스톨러 다운로드 후 실행설치 중 "Android Virtual Device" 항목 체크 유지
macOS공식 사이트에서 .dmg 다운로드 (Apple Silicon/Intel 버전 확인)M1/M2/M3 칩이면 반드시 Apple Silicon용 다운로드
Linux공식 사이트에서 .tar.gz 압축 해제 후 studio.sh 실행64비트 배포판 권장, KVM 가상화 활성화 필요

Tip

  • "SDK가 뭔가요?" — Software Development Kit의 줄임말로, 안드로이드 앱을 만들고 빌드하는 데 필요한 도구와 라이브러리 묶음입니다. Android Studio가 자동으로 관리해주므로 직접 다운로드할 일은 거의 없습니다.
  • 실제 스마트폰이 있다면 USB로 연결해서 바로 테스트할 수 있습니다. 설정 → 휴대전화 정보 → 빌드 번호를 7번 연속 탭하면 "개발자 옵션"이 열리고, 여기서 "USB 디버깅"을 켜면 됩니다. 에뮬레이터보다 훨씬 빠릅니다.

첫 프로젝트 만들기

여기서는 첫 프로젝트 만들기을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

Android Studio를 실행하면 시작 화면에서 New Project를 선택합니다. 템플릿 목록에서 Empty Activity를 고르면, 불필요한 예제 코드 없이 딱 필요한 최소한의 구조로 시작할 수 있습니다. (Compose를 지원하는 최신 Android Studio에서는 Empty Activity가 자동으로 Compose 기반으로 생성됩니다.)
BASH
# 프로젝트 생성이 끝나면 상단 툴바의 초록색 ▶ (Run) 버튼을 누르세요.
# 연결된 실제 기기가 없다면 Android Studio가 에뮬레이터를 자동으로
# 실행하고, 잠시 후 화면에 "Hello Android!" 문구가 뜨는 첫 앱을 볼 수 있습니다.

# 만약 에뮬레이터 목록이 비어있다면:
# 우측 Device Manager 아이콘 클릭 → Create Device → Pixel 8 선택
# → 시스템 이미지(API 34 등) 다운로드 → Finish
설정 항목의미초보자 추천값
Name앱 이름 (사람이 보는 이름)자유롭게 (예: MyFirstApp)
Package name앱의 전 세계 고유 식별자com.example.myfirstapp 같은 역도메인 형식
Save location프로젝트 파일이 저장될 폴더기본값 그대로 사용
Language사용할 프로그래밍 언어Kotlin (기본값)
Minimum SDK앱이 지원할 가장 오래된 안드로이드 버전API 24 (Android 7.0) — 실무에서 널리 쓰이는 기준선

Tip

"Minimum SDK를 낮게 잡으면 더 많은 기기를 지원하지만, 최신 API를 못 쓰는 경우가 생깁니다. 반대로 너무 높게 잡으면 오래된 기기 사용자를 놓칩니다. API 24는 이 균형을 잘 잡은 실무 기준값입니다."

프로젝트 구조 이해

프로젝트 구조 이해은 선택지가 갈리는 지점입니다. 표를 기준으로 각 방법의 쓰임새와 운영상의 차이를 비교해두면 이후 판단이 훨씬 쉬워집니다.

처음 프로젝트를 열면 왼쪽 파일 트리에 낯선 폴더가 잔뜩 보여서 당황할 수 있습니다. 하지만 실제로 매일 손댈 파일은 정해져 있습니다. 아래 표에 나온 것만 기억해도 충분합니다.
경로이게 뭔가요?언제 여나요?
app/src/main/java/.../MainActivity.kt앱이 처음 실행될 때 호출되는 진입점 코드거의 항상 — 여기서 Composable을 연결합니다
app/src/main/res/이미지, 아이콘, 문자열, 색상 같은 리소스 모음이미지나 앱 이름을 바꿀 때
app/src/main/AndroidManifest.xml앱의 이름, 권한, 화면 목록을 선언하는 설정 파일카메라 등 권한이 필요할 때
app/build.gradle.kts이 앱 모듈에서 쓸 라이브러리(의존성)와 빌드 설정새 라이브러리를 추가할 때 — 가장 자주 여는 파일
build.gradle.kts (프로젝트 최상단)프로젝트 전체에 적용되는 공통 빌드 설정거의 열 일 없음

Tip

"Gradle이 뭔가요?" — 안드로이드 프로젝트를 빌드(컴파일 + 패키징)해주는 도구입니다. 다른 언어의 npm, pip 같은 패키지 관리자와 라이브러리 버전 관리 기능을 합친 것이라고 생각하면 됩니다.

Compose 첫걸음: Composable 함수

여기서는 Compose 첫걸음: Composable 함수을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

Compose에서 화면의 모든 조각은 @Composable 어노테이션이 붙은 일반 Kotlin 함수로 만들어집니다. 특별한 문법이 아니라 그냥 함수이기 때문에, 다른 Composable을 호출해서 조합하고, 매개변수를 받아 재사용할 수 있습니다.

아래 예제를 한 줄씩 살펴보면: Column은 자식들을 세로로 쌓는 레이아웃, Text는 글자를 표시, Button은 누를 수 있는 버튼입니다. MainActivity의 setContent { } 블록 안에서 우리가 만든 Composable을 호출하면 화면에 그려집니다.
MainActivity.ktKOTLIN
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

// @Composable: "이 함수는 화면을 그리는 함수입니다" 라는 표시
@Composable
fun Greeting(name: String) {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(text = "안녕하세요, $name!")
        Button(onClick = { /* 버튼을 누르면 실행할 코드 */ }) {
            Text("눌러보세요")
        }
    }
}

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // setContent 안에서 Composable을 호출하면 화면에 그려집니다
        setContent {
            Greeting(name = "AI DevOps")
        }
    }
}

Tip

미리보기(Preview)를 함수 위에 @Preview를 붙이면 앱을 실행하지 않고도 Android Studio 오른쪽 패널에서 바로 UI를 확인할 수 있습니다. 작은 화면 변경을 반복해서 확인할 때 앱을 매번 재실행하지 않아도 되어 매우 편리합니다.

레이아웃 & Modifier

여기서는 레이아웃 & Modifier을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

Compose 레이아웃은 세 가지 기본 컨테이너로 대부분 해결됩니다. Column은 세로로, Row는 가로로 자식들을 배치하고, Box는 자식들을 겹쳐서 쌓습니다. HTML/CSS의 flexbox와 개념이 비슷합니다.

Modifier는 크기, 여백, 정렬, 클릭 이벤트 같은 부가 속성을 체이닝(연쇄 호출) 방식으로 붙이는 도구입니다. 중요한 점은 Modifier를 쓴 순서가 결과에 영향을 준다는 것입니다. 예를 들어 padding을 먼저 주고 클릭 영역을 지정하는 것과, 클릭 영역을 먼저 지정하고 padding을 주는 것은 실제로 다르게 동작합니다. 처음에는 순서를 신경 쓰지 않아도 괜찮지만, 레이아웃이 예상과 다르게 나온다면 Modifier 순서를 의심해보세요.
KOTLIN
@Composable
fun ProfileCard() {
    Row(
        modifier = Modifier
            .fillMaxWidth()      // 가로 폭을 화면 끝까지 채움
            .padding(16.dp),     // 바깥 여백 16dp
        verticalAlignment = Alignment.CenterVertically
    ) {
        Column {
            Text("홍길동")
            Text("Android 개발자")
        }
        Spacer(modifier = Modifier.weight(1f)) // 남은 공간을 모두 차지 (오른쪽 정렬 효과)
        Text("팔로우")
    }
}

Tip

"dp가 뭔가요?" — density-independent pixel의 줄임말로, 화면 해상도가 달라도 물리적으로 비슷한 크기로 보이게 해주는 단위입니다. 웹의 px 대신 항상 dp를 쓴다고 생각하면 됩니다.

상태 관리: remember와 mutableStateOf

여기서는 상태 관리: remember와 mutableStateOf을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

Compose의 핵심 원칙은 "상태(State)가 바뀌면 그 상태를 읽는 UI가 자동으로 다시 그려진다"는 것입니다. 이걸 재구성(recomposition)이라고 부릅니다.

remember는 Composable 함수가 다시 실행되어도(recomposition) 값을 잃어버리지 않게 "기억"해주는 역할이고, mutableStateOf는 그 값이 바뀔 때 Compose에게 "이 값을 읽는 UI들을 다시 그려줘"라고 알려주는 관찰 가능한 상태 홀더입니다. 이 둘을 함께 쓰지 않으면(예를 들어 그냥 var count = 0으로 선언하면) 값은 바뀌어도 화면은 갱신되지 않습니다 — 처음 배우는 분들이 가장 자주 겪는 실수입니다.
KOTLIN
@Composable
fun Counter() {
    // remember: recomposition 간에 값을 유지
    // mutableStateOf: 값이 바뀌면 이 값을 읽는 UI를 자동으로 다시 그림
    // by 키워드를 쓰면 count.value 대신 count로 바로 읽고 쓸 수 있습니다
    var count by remember { mutableStateOf(0) }

    Column {
        Text(text = "카운트: ${count}")
        Button(onClick = { count++ }) { Text("증가") }
    }
}

Tip

화면 회전처럼 Activity가 재생성되는 상황에서도 값을 유지하고 싶다면 remember 대신 rememberSaveable을 사용하세요. 사용법은 거의 동일합니다.

리스트 UI: LazyColumn

여기서는 리스트 UI: LazyColumn을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

앱 화면 대부분은 게시글 목록, 채팅 목록처럼 여러 항목을 나열하는 형태입니다. 이때 일반 Column에 항목을 하나하나 나열하면 항목이 100개, 1000개가 될 때 모두 한 번에 화면에 그려서 성능이 크게 떨어집니다.

LazyColumn은 이름 그대로 "게으르게(lazy)" 동작해서, 실제로 화면에 보이는 항목만 그리고 스크롤할 때마다 필요한 만큼만 추가로 그립니다. 웹 개발의 가상 스크롤(virtual scrolling)과 같은 개념입니다.
KOTLIN
data class Todo(val id: Int, val title: String)

@Composable
fun TodoList(todos: List<Todo>) {
    LazyColumn {
        items(todos, key = { it.id }) { todo ->
            Text(
                text = todo.title,
                modifier = Modifier.padding(12.dp)
            )
        }
    }
}

Tip

items()에 key를 지정하면 목록 중간에 항목이 추가/삭제될 때 Compose가 어떤 항목이 진짜로 바뀌었는지 정확히 알 수 있어서 애니메이션과 성능이 좋아집니다. 특별한 이유가 없다면 항상 key를 지정하는 습관을 들이세요.

화면 전환 (Navigation Compose)

여기서는 화면 전환 (Navigation Compose)을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

앱에 화면이 두 개 이상이라면 화면 사이를 이동하는 방법이 필요합니다. Navigation Compose 라이브러리는 이동 가능한 화면들을 "경로(route)" 이름으로 등록해두고, 코드에서 그 이름을 호출해 이동하는 방식으로 동작합니다. 웹 개발에서 URL 라우팅을 다뤄봤다면 매우 익숙한 개념입니다.
KOTLIN
@Composable
fun AppNavHost() {
    val navController = rememberNavController()

    NavHost(navController = navController, startDestination = "home") {
        composable("home") {
            HomeScreen(onNavigateToDetail = {
                navController.navigate("detail") // "detail" 화면으로 이동
            })
        }
        composable("detail") {
            DetailScreen(onBack = {
                navController.popBackStack() // 이전 화면으로 돌아가기
            })
        }
    }
}

ViewModel과 생명주기

여기서는 ViewModel과 생명주기을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

화면을 회전하면 Android는 기본적으로 Activity를 통째로 다시 만듭니다. 이때 remember로 저장한 상태는 모두 사라집니다. 사용자가 입력하던 텍스트나 불러온 데이터가 화면 회전 한 번에 날아간다면 매우 불편하겠죠.

ViewModel은 이런 화면 재생성에도 살아남는 별도의 클래스입니다. 화면(Composable)은 ViewModel이 들고 있는 상태를 구독만 하고, 실제 데이터를 만들고 바꾸는 로직은 모두 ViewModel 안에 둡니다. 이렇게 역할을 나누면 UI 코드와 비즈니스 로직이 깔끔하게 분리되어 테스트하기도 훨씬 쉬워집니다 (이를 MVVM 아키텍처라고 부릅니다).
KOTLIN
class CounterViewModel : ViewModel() {
    // private set: 외부에서는 읽기만 가능, 수정은 이 클래스 안에서만
    var count by mutableStateOf(0)
        private set

    fun increment() { count++ }
}

@Composable
fun CounterScreen(viewModel: CounterViewModel = viewModel()) {
    Column {
        Text("카운트: ${viewModel.count}")
        Button(onClick = { viewModel.increment() }) { Text("증가") }
    }
}

Tip

viewModel()은 androidx.lifecycle.viewmodel.compose 패키지가 제공하는 함수로, 화면이 재생성되어도 같은 ViewModel 인스턴스를 재사용하도록 자동으로 관리해줍니다. 직접 new로 생성하지 말고 항상 이 함수를 통해 얻으세요.

네트워크 통신 (Retrofit + 코루틴)

여기서는 네트워크 통신 (Retrofit + 코루틴)을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

서버에서 데이터를 가져오는 REST API 호출은 Retrofit 라이브러리와 Kotlin 코루틴의 조합이 실무 표준입니다. 함수 앞에 suspend 키워드를 붙이면 "이 함수는 시간이 걸릴 수 있으니 기다리는 동안 다른 작업(예: 화면 그리기)을 막지 않겠다"는 뜻이 됩니다 — 콜백 지옥 없이 마치 동기 코드처럼 순서대로 작성할 수 있습니다.
KOTLIN
data class User(val id: Int, val name: String)

interface ApiService {
    @GET("users")
    suspend fun getUsers(): List<User>
}

val api: ApiService = Retrofit.Builder()
    .baseUrl("https://api.example.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()
    .create(ApiService::class.java)

class UserViewModel : ViewModel() {
    var users by mutableStateOf<List<User>>(emptyList())
        private set

    fun loadUsers() {
        // viewModelScope: ViewModel이 사라질 때 자동으로 코루틴도 함께 취소됨
        viewModelScope.launch {
            try {
                users = api.getUsers()
            } catch (e: Exception) {
                // 네트워크 오류, 서버 오류 등을 여기서 처리
            }
        }
    }
}

Tip

viewModelScope 안에서 실행한 코루틴은 화면이 사라지면(ViewModel이 정리되면) 자동으로 취소됩니다. 화면을 나갔는데도 계속 네트워크 요청이 진행되는 메모리 누수를 방지해주므로, 반드시 viewModelScope를 통해 호출하세요.

권한 처리

여기서는 권한 처리을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

카메라, 위치, 저장소처럼 사용자의 민감한 정보에 접근하려면 두 단계가 필요합니다. 첫째, AndroidManifest.xml에 어떤 권한이 필요한지 선언합니다. 둘째, 앱 실행 중에 사용자에게 실제로 권한을 요청하고 승인을 받아야 합니다 (Android 6.0 이상은 설치 시점이 아니라 실제 사용 시점에 물어보는 "런타임 권한" 방식입니다).
XML
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.CAMERA" />
KOTLIN
@Composable
fun CameraScreen() {
    val context = LocalContext.current
    val launcher = rememberLauncherForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { granted ->
        if (granted) {
            // 권한이 승인된 경우의 처리
        } else {
            // 거부된 경우 — 이유를 설명하는 안내 UI를 보여주는 것이 좋습니다
        }
    }

    Button(onClick = {
        launcher.launch(Manifest.permission.CAMERA)
    }) {
        Text("카메라 권한 요청")
    }
}

Tip

사용자가 이유도 모른 채 갑자기 권한 팝업을 보면 거부할 확률이 높아집니다. 권한을 요청하기 직전에 "왜 이 권한이 필요한지" 설명하는 안내 문구를 먼저 보여주는 것이 실무에서 승인율을 높이는 좋은 습관입니다.

로컬 데이터 저장 (DataStore)

여기서는 로컬 데이터 저장 (DataStore)을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

앱을 껐다 켜도 유지되어야 하는 간단한 설정값(예: 다크 모드 여부, 로그인 유지 여부)은 DataStore에 저장합니다. 예전에는 SharedPreferences를 썼지만, DataStore는 코루틴 기반이라 UI 스레드를 막지 않고, 데이터 흐름을 Flow로 관찰할 수 있어 최신 프로젝트에서는 DataStore가 권장됩니다. 여러 테이블을 다루는 복잡한 데이터라면 Room이라는 별도의 로컬 데이터베이스 라이브러리를 사용합니다.
KOTLIN
val Context.dataStore by preferencesDataStore(name = "settings")
val DARK_MODE_KEY = booleanPreferencesKey("dark_mode")

// 저장하기
suspend fun setDarkMode(context: Context, enabled: Boolean) {
    context.dataStore.edit { prefs -> prefs[DARK_MODE_KEY] = enabled }
}

// Flow로 값 관찰하기 — 값이 바뀔 때마다 자동으로 새 값이 흘러옴
fun darkModeFlow(context: Context): Flow<Boolean> =
    context.dataStore.data.map { prefs -> prefs[DARK_MODE_KEY] ?: false }

테스트 작성하기

여기서는 테스트 작성하기을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

"UI를 어떻게 테스트하나요?"는 많은 초보자가 건너뛰는 부분이지만, Compose는 UI 테스트를 꽤 쉽게 만들어줍니다. createComposeRule()로 테스트용 화면을 띄우고, 텍스트나 버튼을 찾아 클릭한 뒤 결과를 확인하는 식입니다. ViewModel처럼 UI와 분리된 로직은 순수 Kotlin 단위 테스트로 훨씬 빠르게 검증할 수 있습니다.
KOTLIN
class CounterTest {
    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun clickingButton_incrementsCounter() {
        composeTestRule.setContent { Counter() }

        // 초기 상태 확인
        composeTestRule.onNodeWithText("카운트: 0").assertExists()

        // 버튼 클릭
        composeTestRule.onNodeWithText("증가").performClick()

        // 클릭 후 상태 확인
        composeTestRule.onNodeWithText("카운트: 1").assertExists()
    }
}

Tip

모든 화면을 다 테스트할 필요는 없습니다. 처음에는 로그인, 결제처럼 실패하면 치명적인 핵심 흐름부터 테스트를 작성하는 것을 추천합니다.

빌드 및 배포

여기서는 빌드 및 배포을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

테스트가 끝났다면 이제 실제 사용자에게 앱을 배포할 차례입니다. 개발 중에는 서명 없는 디버그용 APK로 충분하지만, Play 스토어에 올리려면 반드시 디지털 서명이 된 AAB(Android App Bundle) 파일이 필요합니다. 서명은 "이 앱이 진짜 나(개발자)가 만든 것"이라는 것을 증명하는 절차입니다.
BASH
# 개발 중 테스트용 디버그 APK 빌드
./gradlew assembleDebug

# Play 스토어 제출용 릴리스 App Bundle 빌드
./gradlew bundleRelease
단계해야 할 일
1. 서명 키 생성Android Studio의 Build → Generate Signed Bundle/APK 마법사로 keystore 파일을 만들고 안전하게 보관 (분실하면 같은 앱을 업데이트할 수 없습니다)
2. 릴리스 빌드위 keystore로 서명된 AAB 파일을 빌드
3. Play Console 등록Google Play Console에 개발자로 등록 (1회 등록비 필요) 후 AAB 업로드
4. 단계적 출시내부 테스트 → 비공개 테스트 → 전체 공개 순서로 단계적으로 배포하는 것이 안전합니다

다음 단계

이 섹션은 다음 단계을 실무 관점에서 정리합니다. 개념을 외우기보다, 어떤 상황에서 이 기준을 꺼내 쓸지에 초점을 맞춰보세요.

여기까지 왔다면 Android 앱 하나를 처음부터 끝까지 만들고 배포할 수 있는 기본기를 모두 갖춘 것입니다. 다음으로는 Hilt(의존성 주입으로 코드 구조를 더 깔끔하게), Room(복잡한 로컬 데이터베이스), StateFlow(ViewModel의 상태 관리를 더 정교하게), Material 3 디자인 시스템을 깊이 파보는 것을 추천합니다. 막히는 부분이 있다면 이 가이드의 각 섹션으로 언제든 다시 돌아와 복습하세요.

Android 실무 설계

Android 실무 설계은 선택지가 갈리는 지점입니다. 표를 기준으로 각 방법의 쓰임새와 운영상의 차이를 비교해두면 이후 판단이 훨씬 쉬워집니다.

Android는 Compose UI와 비즈니스 로직을 ViewModel 경계로 분리해야 합니다. State는 단일 소스(single source of truth)로 관리하고 UI는 그 상태를 구독만 하는 구조가 유지보수에 유리합니다.
결정 지점확인 질문실무 기준
경계Android 코드에서 바뀌기 쉬운 부분은 어디인가?입출력, 설정, 외부 연동, 핵심 규칙을 분리합니다.
상태상태가 어디서 생성되고 어디서 사라지는가?상태 소유자와 수명 주기를 코드로 드러냅니다.
장애실패했을 때 호출자는 무엇을 받는가?timeout, fallback, error contract를 먼저 정합니다.

Android 운영 기준

이 섹션은 Android 운영 기준을 실무 관점에서 정리합니다. 개념을 외우기보다, 어떤 상황에서 이 기준을 꺼내 쓸지에 초점을 맞춰보세요.

운영에서는 생명주기(Lifecycle)에 맞춘 코루틴 스코프(viewModelScope), 메모리 누수 방지, 백그라운드 작업(WorkManager), APK/AAB 크기 관리가 핵심입니다.

Tip

  • viewModelScope 사용
  • State 단일 소스
  • ComposeTestRule UI 테스트
  • 프로세스 재생성 대응

Android 검증 전략

Android 검증 전략은 선택지가 갈리는 지점입니다. 표를 기준으로 각 방법의 쓰임새와 운영상의 차이를 비교해두면 이후 판단이 훨씬 쉬워집니다.

Compose는 UI 테스트(ComposeTestRule)와 ViewModel 단위 테스트를 분리하고, 화면 회전·프로세스 재생성 시나리오를 회귀 테스트에 포함해야 합니다.
품질 축검증 방법완료 기준
정확성정상/실패 케이스를 자동화합니다.핵심 시나리오가 재현 가능하게 통과합니다.
회귀 방지버그 수정 시 동일 케이스를 테스트로 남깁니다.같은 장애가 다시 배포되지 않습니다.
운영성로그, 메트릭, 알림을 확인합니다.문제가 생겼을 때 원인 추적 경로가 있습니다.
← 이전 가이드Kotlin다음 가이드 →Flutter