[ADG] Android Developer Guide 유용한 내용들

오늘·2022년 7월 13일

안드로이드 개발자 가이드에서 봤던 유용한 내용들을 적어놓으려 한다.
(계속 수정될 예정)

Kotlin 스타일 가이드

링크

쉽게 말하면 코틀린의 이름 규칙을 정리해놓은 문서이다.

리팩토링

출력을 변경하지 않고 더 효율적으로 또는 더 쉽게 작업할 수 있도록 코드를 변경하는 것

repeat(n) {}

{} 안의 내용을 n번 반복하는 루프

// n번 =를 출력 후 개행하는 함수
fun printBorder(n: Int) {
	repeat(n) {
    	print("=")
    }
    println()
}

하향식 개발

큰 그림부터 시작하여 세부정보를 추가하는 것

어떻게 프로그램을 구성할지 즉, 변수, 함수의 이름과 인수 등을 먼저 main에 작성해놓고, 세부적인 구현은 그 후에 하는 방식

Package name

Android 시스템에서 앱을 고유하게 식별하기 위해 사용하는 이름

테스트

소프트웨어 관점에서 테스트는 소프트웨어가 올바르게 작동하는지 확인하는 구조화된 방법입니다.

테스트란 정확히 무엇인가요? 테스트는 앱 코드의 일부를 실행하는 Android Studio 프로젝트에 포함된 코드 조각으로, 앱 코드가 예상대로 동작하는지에 따라 테스트에 통과 하거나 실패할 수 있습니다.

단위 테스트(Unit Test)

  • Android의 로컬 테스트는 일반적으로 단위 테스트임.
  • test 폴더에 있음.
  • 코드를 직접 테스트함.
  • 단위 테스트는 JVM에서 돌아감.
  • app/build.gradle 파일에 testImplementaton으로 표시된 종속 항목
  • org.junit.test 라이브러리에서 가져온 @Test Annotation을 달아서 컴파일러가 이 Annotation이 표시된 메서드는 테스트임을 알 수 있음.
  • assertEqual() 메서드는 예상 값(expected)이 비즈니스 로직을 통해 가져온 실제 값(actual)과 같아야 한다고 어설션 하는 메서드
    • 어설션 메서드는 단위 테스트의 최종 목표
  • 궁극적으로 코드에서 가져온 결과가 특정 상태에 있음을 어설션하는 것이 좋음.
  • JUnit 라이브러리에서 사용하는 일반적인 어설션
    • assertEquals()
    • assertNotEquals()
    • assertThat()
    • assertTrue()
    • assertFalse()
    • assertNull()
    • assertNotNull()

계측 테스트(Instrumented Test)

  • 일반적으로 UI 테스트를 나타내는 용어.
  • 코드를 직접 테스트하지 않음.
  • 계측 테스트는 사용자 기기 또는 에뮬레이터에서 돌아감.
  • app/build.gradle 파일에 androidTestImplementation으로 표시된 종속 항목

계측 테스트 codelab

테스트에서 반복을 방지하는 Annotation

@RunWith(AndroidJUnit4:class)
class OrderOfTestAnnotations {
	
    @Before
    fun setupFunction() {
    	println("Set up function")
    }
    
    @Test
    fun test_a() {
    	println("Test a")
    }
    
    @Test
    fun test_b() {
    	println("Test b")
    }
    
    @Test
    fun test_c() {
    	println("Test c")
    }
    
    @After
    fun tearDownFunction() {
    	println("Tear down function")
    }
    
    companion object {
    	@BeforeClass
        @JvmStatic
        fun setupClass() {
        	println("Set up class")
        }
        
        @AfterClass
        @JvmStatic
        fun tearDownClass() {
        	println("Tear down class")
        }
    }
}
  • 실행 결과
Set up class
Set up function
Test a
Tear down function
Set up function
Test b
Tear down function
Set up function
Test c
Tear down function
Tear down class
  • `@Before

    • 각 Test 함수가 실행되기 전에 한 번 실행
  • @After

    • 각 Test 함수가 실행된 후 한 번 실행
  • @BeforeClass

    • Test class가 실행되기 전에 한 번 실행
    • @JvmStatic Annotation과 함께 사용되어야 하며, companion object 내부에 포함되어야 함.
  • @AfterClass

    • Test class가 실행된 후 한 번 실행
    • @JvmStatic Annotation과 함께 사용되어야 하며, companion object 내부에 포함되어야 함.

APK

APK는 기기나 에뮬레이터에서 앱을 실행하는 데 필요한 파일과 모든 코드를 포함하는 압축 파일입니다.

번역

앱을 작성할 때는 특정 시점에 다른 언어로 번역될 수 있음을 기억해야 합니다.

접근성

접근성을 위한 적절한 코딩 사례를 따르면 장애가 있는 사용자를 포함하여 사용자가 모두 더 쉽게 앱을 탐색하고 앱과 상호작용할 수 있습니다.

TextView의 도구텍스트 속성

  • 도구 텍스트 속성은 Android Studio 내의 Design Editor에만 표시되고 실제 기기 또는 에뮬레이터에서 앱을 실행할 때는 표시되지 않음.
  • XML 상에서 tools:text 를 통해 참조 가능.

Activity

Activity는 앱이 UI를 그리는 창을 제공합니다.

  • 일반적으로 Activity는 실행되는 앱의 전체 화면을 차지함.
  • 모든 앱에는 하나 이상의 Activity가 있음.
  • 최상위 수준 또는 첫 번째 Activity를 MainActivity라고 함.
  • 각 Activity에는 특정 목적이 있음.

Auto Import

  • File > Settings > Editor > General > Auto Import

  • Add unambiguous imports on the fly

    • 모호하지 않은 import 문은 자동으로 추가
  • Optimize imports on the fly

    • 사용되지 않는 import 문은 자동으로 삭제

Android 스타일 가이드

팀으로 작업할 때 팀원들은 유사한 방식으로 코드를 작성하여 코드 전체에서 일관성이 유지되도록 하는 것이 좋습니다. 이런 이유로 Android에는 Android 코드 작성 방법에 관한 스타일 가이드(이름 지정 규칙, 서식 지정 및 준수할 기타 우수 사례 등)가 있습니다.

Android 개발자용 Kotlin 스타일 가이드

코드 서식 다시 지정

  1. ctrl+A 로 코드를 전체 선택한다.
  2. ctrl+Alt+L로 코드를 자동으로 깔끔하게 변경할 수 있다.
    • Android Studio 메뉴 중 Code > Reformat Code 로 설정할 수도 있다.

코드에 주석 달기

코드에 주석을 추가하여 작성한 코드에서 발생하는 작업을 설명합니다. 코드가 점점 복잡해짐에 따라 이렇게 작동하도록 코드를 작성한 이유를 기록하는 것도 중요합니다. 변경하려고 나중에 코드로 돌아오면 코드가 하는 작업은 여전히 명확하지만 코드를 이렇게 작성한 이유는 기억나지 않을 수도 있습니다.

작성한 각 클래스 및 각 메서드에 주석을 추가하는 것이 일반적입니다. 주석 시작과 끝 부분에 /****/ 기호를 사용하여 시스템에 코드가 아니라고 알립니다.

메서드 내에서는 코드 리더에 도움이 된다면 자유롭게 주석을 추가할 수 있습니다. 주석 시작 부분에 // 기호를 사용할 수 있습니다.

주석과 서식이 모두 변경되면 앱을 다시 실행하여 예상대로 작동하는지 확인하는 것이 좋습니다.

View가 겹쳐있을 때 선택하는 법(꿀팁)

UI 구성요소를 더 추가하고 제약조건을 추가 및 삭제하므로 View
다른 View와 겹쳐 뒤에 있는 View를 선택하기 어려울 수 있습니다. 이 경우에는 대신 Component Tree에서 View를 선택할 수 있습니다.

Resource Manager 위치

View > Tool Windows > Resource Manager

  • Project 창 왼쪽에도 있음.

ImageView의 도구 srcCompat 속성

  • Android Studiod의 Design 뷰 내에서만 보이는 이미지
  • 앱을 빌드할 때만 개발자에게 표시되고 실제로 에뮬레이터나 기기에서 앱을 실행할 때는 표시되지 않음.

밀도 독립형 픽셀(dp)

밀도 독립형 픽셀(dp)을 단위로 사용하여 이러한 크기를 정의하면 픽셀 해상도가 다른 기기에서 이미지 크기가 적절하게 조정됩니다.

(자동) 테스트가 중요한 이유

  1. 앱의 규모가 커지면 수동 테스트는 자동 테스트를 작성하는 것보다 훨씬 많은 노력이 필요하다.
  2. 전문가 수준의 앱 작업에서 사용자층이 넓을 때, 다양한 버전의 Android를 실행하는 여러 유형의 기기를 고려해야 한다.
  3. 새 코드를 출시하기 전에 테스트를 실행하면, 예쌍치 못한 동작이 있는 상태로 앱이 출시되지 않도록 기존 코드를 변경할 수 있다.

Annotation

Annotation은 코드가 컴파일되는 방법을 변경할 수 있는 코드의 메타데이터 태그로 생각하면 됩니다.

Log

Log 클래스는 Logcat에 메시지를 씁니다.
Android 앱에서 출력 로깅 권장사항은 Log 클래스를 사용하는 것입니다.

출력 로깅 함수

  • Log.v() : 자세한 메시지
  • Log.d() : 디버그 메시지
  • Log.i() : 정보 메시지
  • Log.w() : 경고 메시지
  • Log.e() : 오류 메시지

매개변수

  • tag : 로그 메시지의 소스를 식별하는 문자열(보통 텍스트를 로그한 클래스 이름)
  • msg : 실제 로그 메시지

로그 수준

  • verbose, debug 수준의 Log는 출시 빌드에서 삭제되므로 로그 구문에서 부수 효과(코드의 값 수정)가 발생하지 않도록 해야 함. (출시 빌드에서 무한 루프 발생 가능)

클래스에서 TAG 상수를 선언하는 것이 좋습니다.
const val TAG = "MainActivity"
그리고 아래와 같이 후속 로그 메서드 호출에서 이를 사용합니다.
Log.d(TAG, "onCreate Called")

Logcat

Logcat은 메시지를 기록하는 콘솔입니다. Log.d()메서드나 기타 Log 클래스 메서드를 사용하여 로그에 명시적으로 전송하는 메시지를 비롯하여 앱에 관한 Android의 메시지가 여기에 표시됩니다.

Logcat에는 많은 메시지가 포함될 수 있지만 대부분은 유용하지 않습니다. Logcat 항목을 다양한 방식으로 필터링할 수 있지만 검색이 가장 쉬운 방법입니다.

로그 메시지에는 날짜 및 시간, 패키지 이름, 로그 태그, 실제 메시지가 포함됩니다.

StackOverflow에 검색할 때

답변이 유사하지만 정확히 같지는 않은 질문이 많을 수 있으므로 답변을 직접 검색할 때 다음 팁을 염두에 두세요.

  1. 답변이 얼마나 오래되었나요? 몇 년 전 답변은 더 이상 관련이 없거나 오래된 버전의 언어나 프레임워크를 사용하고 있을 수 있습니다.
  2. 답변에서 자바나 Kotlin을 사용하나요? 문제가 특정 언어나 특정 프레임워크에만 관련이 있나요?
  3. accepted(수락됨) 로 표시되거나 찬성 투표가 많은 답변이 더 유용할 수 잇지만 다른 답변도 여전히 중요한 정보를 제공할 수 있다는 점에 유의합니다.

스택 오버플로우 질문 가이드라인

문자열 리소스 사용 방법

Android에서는 거의 모든 것이 리소스입니다. 따라서 앱에서 액세스할 수 있는 리소스를 정의하는 것이 Android 개발의 필수 요소입니다.

리소스는 색상, 이미지, 레이아웃, 메뉴, 문자열 값을 정의하는 것부터 모든 것에 사용됩니다. 이 경우 이점은 어떤 것도 하드코딩되지 않는다는 점입니다. 모든 것이 이러한 리소스 파일에서 정의되고 애플리케이션의 코드 내에서 참조될 수 있습니다. 이러한 리소스 중 가장 간단하고 가장 일반적인 것은 유연하고 현지화된 텍스트를 허용하는 문자열 리소스를 사용하는 것입니다.

codelab 문자열 리소스 사용법 링크

추상 클래스

추상 클래스는 완전히 구현되지 않아서 인스턴스화 할 수 없는 클래스입니다. 스케치라고 생각하면 됩니다. 스케치를 통해 무언가에 관한 아이디어와 계획을 통합하지만 그 무언가를 빌드하기에는 일반적으로 정보가 충분하지 않습니다. 스케치(추상 클래스)를 사용하여 청사진(클래스)을 만들고 청사진을 통해 실제 객체 인스턴스를 빌드합니다.

constructor

클래스 헤더에 class SquareCabin(residents: Int) ... 가 표시됩니다.
실제로는 class SquareCabin constructor(residents: Int) ...의 약어입니다.
constructor는 클래스에서 객체 인스턴스를 만들 때 호출됩니다. 예를 들어 SquareCabin(4)를 호출하면 SquareCabinconstructor가 호출되어 객체 인스턴스를 초기화합니다.
constructor는 전달된 인수를 비롯하여 클래스의 모든 정보에서 인스턴스를 빌드합니다. 클래스가 상위 클래스에서 속성과 함수를 상속받을 때 constructor는 상위 클래스의 constructor를 호출하여 객체 인스턴스 초기화를 완료합니다.

open 키워드

기본적으로 Kotlin에서 클래스는 final 클래스이며 서브클래스로 분류할 수 없습니다. abstarct 클래스나 open 키워드로 표시된 클래스에서만 상속할 수 있습니다.

생성자 인수 순서

  • 상위 클래스의 생성자에 있는 인수를 하위 클래스의 생성자에서 제일 앞에 배치하여 상위 클래스와 하위 클래스의 인수 순서를 맞춰주는 것이 좋다.

XML의 태그

  • 빈 요소 태그(empty-element-tag)
    • 두 줄(또는 속성이 없는 경우 한 줄)에 빈 요소 태그를 표시할 수도 있음.
<TextView
    android:text="Hello World!"
/>
  • 시작 태그(start-tag), 종료 태그(end-tag)
    • 내부에 다른 요소를 보유할 수 있어야 할 때는 반드시 시작 태그와 종료 태그 사용.
<TextView
    android:text="Hello World!"
></TextView>

Android Jetpack

이 UI 구성요소는 androidx로 시작하므로 Jetpack의 일부인 것을 알 수 있습니다.

xmlns

xmlnsXML 네임스페이스를 나타내고 각 줄은 스키마나 이러한 단어와 관련된 속성의 어휘를 정의합니다. 예를 들어 android: 네임스페이스는 Android 시스템에서 정의한 속성을 표시합니다. 레이아웃 XML의 속성은 모두 이러한 네임스페이스 중 하나로 시작합니다.

리소스 ID

리소스 ID는 요소의 고유한 리소스 이름입니다. Layout Editor로 View나 다른 리소스를 추가하면 Android 스튜디오가 리소스 ID를 자동으로 할당합니다. XML을 수동으로 입력할 때는 리소스 ID를 직접 명시적으로 선언해야 합니다. XML 파일의 새로운 뷰 ID는 @+id 접두사로 정의해야 하고 이 접두사는 Android 스튜디오에 이 ID를 새 리소스 ID로 추가하라고 지시합니다.

리소스를 설명하는 이름을 선택하면 무엇을 참조하는지 알 수 있지만 모두 소문자여야 하고 여러 단어는 밑줄로 구분해야 합니다.

앱 코드에서 리소스 ID를 참조할 때 R.<type>.<name>(예: R.string.roll)을 사용합니다. View ID의 경우 <type>id(예: R.id.button)입니다.

입력 방법 유형 지정

Edit Text에서 사용하는 inputType 속성의 종류

ConstraintLayout

  • 한 레이아웃에 하위 뷰 여러 개를 배치할 때 가장 적합하고 유연한 Layout

ConstraintLayout에서 match_parent

상위 요소의 너비와 같기를 바라므로 너비를 match_parent로 설정해야 한다고 생각할 수 있습니다. ConstraintLayout의 UI 요소에는 match_parent를 설정할 수 없습니다. 대신 뷰의 시작 및 끝 가장자리를 제한하고 너비를 0dp로 설정해야 합니다. 너비를 0dp로 설정하면 시스템에서 너비를 계산하지 않고 뷰에 적용된 제약 조건을 일치시키려고만 합니다.

match_parentConstraintLayout의 뷰에는 사용할 수 없습니다. 대신 일치 제약 조건을 의미하는 0dp를 사용하세요

라디오 버튼 가이드

링크

Gradle

Gradle은 Android 스튜디오에서 사용하는 자동화된 빌드 시스템입니다. 개발자가 코드를 변경하거나 리소스를 추가하거나 그 외의 방식으로 앱을 변경할 때마다 Gradle이 변경된 사항을 파악하여 앱을 다시 빌드하는 데 필요한 조치를 취합니다. 또한 에뮬레이터 또는 실제 기기에 앱을 설치하고 실행을 제어합니다.

뷰 결합(View Binding)

Android 공식 문서

Android 프레임워크는 여기에 필요한 작업(View의 ID가 주어지면 이 뷰에 대한 참조를 반환하는 작업)을 정확히 실행하는 findViewById() 메서드를 제공합니다. 이 접근 방식은 효과적이지만 앱에 뷰를 더 많이 추가하고 UI가 더 복잡해짐에 따라 finViewById()를 사용하는 것이 번거로워질 수 있습니다.

편의를 위해 Android는 뷰 결합(View Binding)이라는 기능도 제공합니다. 사전에 조금만 더 작업하면 뷰 결합을 통해 UI의 뷰에서 메서드를 훨씬 더 쉽고 빠르게 호출할 수 있습니다. Gradle에서 앱의 뷰 결합을 사용 설정하고 몇 가지 코드를 변경해야 합니다.

결합(Binding) 클래스 이름은 XML 파일의 이름을 파스칼 표기법으로 변환하고 이름 끝에 Binding을 추가한 형태가 됩니다. 마찬가지로 각 뷰를 위한 참조는 밑줄을 삭제하고 뷰 이름을 카멜 표기법으로 변환하여 생성됩니다. 예를 들어 파스칼 표기법의 경우 activity_main.xmlActivityMainBinding이 되고 binding.textView@id/text_view에 액세스할 수 있습니다.

체이닝(Chaining)

  • 참조를 이어 붙여서 호출하는 것.
binding.costOfService.text
  • binding.costOfService 라는 UI 요소에 대한 참조에 곧바로 .text를 붙여서 해당 요소의 text 속성을 가져오는 것.
    • 참조에 곧바로 참조를 호출

NumberFormat

Android 개발자 문서

Kotlin은 다양한 유형의 숫자 형식을 지정하는 메서드를 제공합니다. 그런데 팁 금액은 약간씩 다르며 통화 가치를 나타냅니다. 국가마다 서로 다른 통화를 사용하며 십진수 형식 지정 규칙이 다릅니다. 예를 들어 1234.56의경우 미국 달러로는 $1,234.56 형식으로 표시되지만 유로화로는 €1.234,56 형식으로 표시됩니다. 다행히 Android 프레임워크에서는 숫자를 통화 형식으로 지정하는 메서드를 제공하므로 개발자가 모든 경우의 수를 알 필요가 없습니다. 사용자가 스마트폰에서 선택한 언어 및 기타 설정에 따라 시스템이 자동으로 통화 형식을 지정합니다.

// 숫자를 통화 형식으로 지정하는 데 사용할 수 있는 숫자 형식 지정 클래스
NumberFormat.getCurrencyInstance()

문자열 매개변수

Android 개발자 문서

  • 숫자를 문자열의 시작 부분이나 중간 부분에 표시하는 등 언어마다 다른 위치에 표시해야하는 문자가 있을 경우 사용

Inspect Code

회색 선(경고를 표시하는 밑줄)은 매우 감지하기 어려워 간과하기 쉽습니다. 파일 전체를 검토하여 회색 선을 더 많이 찾을 수도 있지만, 모든 추천을 확인할 수 있는 더 간단한 방법이 있습니다.

  • 검사(Inspect)할 코드 파일을 열고 마우스 오른쪽 클릭 > Analyze > Inspect Code... 선택
  • OK를 클릭하면 해당 코드에 대한 경고를 모두 표시해줌.
  • 화면 하단의 Inspection Result를 통해 코드를 간편하게 수정할 수 있음.

머티리얼(Material)

머티리얼은 개발자가 Android와 기타 플랫폼에서 고품질 디지털 환경을 구축할 수 있도록 Google이 만든 설계 시스템입니다. 전체 머터리얼 시스템에는 앱에 맞는 시각적 디자인, 모션 디자인, 상호작용 디자인에 관한 가이드라인이 포함되어 있습니다.

머티리얼 디자인 접근성

머티리얼 디자인

머티리얼 디자인은 물체가 빛을 반사하고 그림자를 드리우는 방식을 포함하여 실제 세계와 질감에서 영감을 받았습니다. 읽기 쉽고 매력적이며 일관된 방식으로 앱 UI를 빌드하는 방법에 관한 가이드라인을 제시합니다.

색상 시스템

Material Studies

Material Studies - 머티리얼을 이용한 예제를 통한 학습

머티리얼 테마

머티리얼 테마를 사용하면 색상, 서체, 도형을 맞춤설정하는 방법으로 앱에 맞게 머티리얼 디자인을 조정할 수 있습니다. 머터리얼 디자인에는 그대로 사용할 수 있도록 기본으로 제공되는 기준 테마가 있습니다. 이 테마를 원하는 만큼 맞춤설정하여 머터리얼을 앱에 적합하게 할 수 있습니다.

머티리얼 구성요소 테마

MDC를 사용한 머티리얼 테마

MDC를 사용한 어두운 테마

색상에 관한 설명

색은 우리 주변, 즉 실제 세계와 디지털 세계 모두에 있습니다. 색에 관해 첫 번째로 알아야 하는 것은 사람마다 색을 보는 방식이 다르다는 것입니다. 따라서 사용자가 앱을 효과적으로 사용할 수 있도록 앱의 색상을 선택하는 것이 중요합니다. 충분히 대비되는 색을 사용하여 색상을 선택하는 것은 더 액세스하기 쉬운 앱을 빌드하는 방법 중 하나입니다.

색상은 색의 빨간색, 녹색, 파란색(RGB) 구성요소를 나타내는 3개의 16진수 숫자(#00~#FF(0~255))로 표현할 수 있습니다. 숫자가 클수록 구성요소의 색이 더 많이 포함됩니다.

또한, 색상은 투명도를 나타내는 알파 값(#00~#FF)을 포함하여 정의할 수 있습니다(#00=0%=완전 투명, #FF=100%=완전 불투명). 알파 값이 포함되는 경우 이 값은 4개의 16진수 숫자(ARGB) 중 첫 번째 숫자입니다. 알파 값이 포함되지 않으면 이 값은 #FF=100%, 즉 불투명으로 간주됩니다.

머티리얼 구성요소(Material Components)

머티리얼 구성요소는 앱에서 머티리얼 스타일을 더 쉽게 구현할 수 있는 일반적인 UI 위젯입니다.

머티리얼 구성요소를 사용하면 앱이 사용자 기기에 있는 다른 앱과 함께 더 일관된 방식으로 작동합니다. 이렇게 하면 한 앱에서 학습된 UI 패턴이 다음 앱에 이전될 수 있습니다. 따라서 사용자는 앱을 사용하는 방법을 훨씬 더 빠르게 배울 수 있습니다. 가능하면 항상(비 머티리얼 위젯이 아닌) 머티리얼 구성요소를 사용하는 것이 좋습니다. 또한 머티리얼 구성요소는 유연성과 맞춤설정 가능성이 더 높습니다.

  • 최근 머티리얼 디자인 가이드라인을 따르도록 구성하는 것이 좋음.
  • 머티리얼 디자인 구성요소를 사용하면 라이브러리가 업데이트될 때 자동으로 앱의 위젯도 업데이트 됨.

Android에서 제공하는 머티리얼 디자인 구성요소

Android의 머티리얼 구성요소 시작하기

아이콘

아이콘은 의도한 기능을 시각적으로 전달하여 사용자가 인터페이스를 이해하는 데 도움을 주는 기호입니다. 아이콘 디자인은 종종 필요한 최소한의 수준으로 세부 표현을 줄여서 사용자에게 인식되도록 만듭니다.

앱의 아이콘의 경우 다양한 화면 밀도에 맞는 여러 버전의 비트맵 이미지를 제공하는 대신 벡터 드로어블을 사용하는 것이 좋습니다.

머티리언 디자인은 대부분의 요구에 부합하는 다수의 아이콘을 일반적인 카테고리로 정리하여 제공합니다.

아이콘 목록

이러한 아이콘은 5개 테마(채워짐, 윤곽선 있음, 둥근 모서리, 투톤, 각진 모서리) 중 하나를 사용하여 그릴 수 있으며 색상을 적용할 수 있습니다.

Android Studio의 Asset Studio에서 직접 이 아이콘을 벡터 드로어블로 만들 수 있습니다.

  • 아이콘 파일의 이름을 지정할 때는 접두어 ic_를 사용하는 것이 좋음.

테마

스타일을 사용하여 글꼴 색상, 글꼴 크기, 배경 색상과 같은 View의 속성을 지정할 수 있습니다.

테마는 개별 View뿐 아니라 앱, 액티비티 또는 뷰 계층 구조 전체에 적용되는 스타일의 모음입니다. 앱, 액티비티, 뷰 또는 뷰 그룹에 테마를 적용하면 요소와 하위 요소 전체에 동일한 테마가 적용됩니다. 또한, 테마를 사용하여 뷰가 아닌 요소(상태 표시줄 및 창 배경)에도 스타일을 적용할 수 있습니다.

테마는 나중에 스타일, 레이아웃 등에 참조할 수 있는 명명된 리소스(테마 속성이라고 함)의 모음입니다. 개별 View 뿐만 아니라 전체 앱, Activity, 뷰 계층 구조에도 테마를 지정할 수 있습니다.

테마 색상 자세히 알아보기

Android 스타일 지정: 테마와 스타일

Android 스타일 지정: 일반적인 테마 속성

Android용 머터리얼 구성요소 테마 설정

서체 테마 설정

어두운 테마

앱 템플릿에서는 기본 밝은 테마가 포함되어 있으며 어두운 테마 변형도 포함되어 있습니다. 어두운 테마는 어둡고 더 부드러운 색상을 사용하며 아래와 같은 이점이 있습니다.

  • 전력 사용을 크게 줄일 수 있습니다(기기의 화면 기술에 따라 다름).
  • 시력이 낮은 사용자와 밝은 빛에 민감한 사용자의 가시성을 개선합니다.
  • 조명이 어두운 환경에서 더 편하게 기기를 사용할 수 있습니다.

어두운 테마의 색상 선택하기

어두운 테마의 색상은 읽기 쉬워야 합니다. 어두운 테마는 제한된 강조 색상으로 어두운 표면 색상을 사용합니다. 가독성을 보장하기 위해 기본 색상은 항상 밝은 테마의 기본 색상보다 더 낮은 버전의 채도를 사용합니다.

어두운 테마에서 더 많은 유연성과 사용성을 제공하려면 기본 색상 테마(900~500 사이의 강렬한 톤) 대신 어두운 테마의 밝은 톤(200~50)을 사용하는 것이 좋습니다.
앱에서는 밝은 색상을 기본 색상으로 사용하고 기본 색상을 변형으로 사용하게 됩니다.

어두운 테마에서 앱 바 및 그 외의 넓은 영역은 기본적으로 기본 색상 대신 어두운 배경(colorSurface)으로 표시됩니다. 이는 머티리얼 어두운 테마의 경우 넓은 표시 영역에서 밝은 색상을 더 적게 사용하도록 권장되기 때문입니다. 버튼 또는 그 외의 작은 요소는 정의된 기본 색상을 표시합니다.

색상 도구(Color Tool)

색상을 선택하는 가장 쉬운 방법은 머터리얼 팀에서 제공하는 웹 기반 앱인 색상 도구를 사용하는 것입니다. 이 도구는 미리 정의된 색상의 팔레트를 제공하며 이를 통해 다양한 UI 요소에 사용된 색상이 어떻게 보이는지 쉽게 확인할 수 있습니다.

색상 대비

앱의 접근성을 높이려면 색상 대비가 매우 높아야 합니다. 작은 텍스트의 경우 4.5:1 이상, 큰 텍스트의 경우 3.0:1 이상이어야 합니다.

머터리얼 팔레트 생성기

머터리얼 팔레트 생성기를 사용하여 보조 색상을 선택할 수도 있습니다. 개발자가 기본 색상을 선택할 수 있으며, 선택된 기본 색상을 바탕으로 생성기에서 보색, 유사색 또는 삼색인 색상을 추천해줍니다.

밀도 한정자

  • mdpi : 중밀도 화면의 리소스(~160dpi)
  • hdpi : 고밀도 화면의 리소스(~240dpi)
  • xhdpi : 초고밀도 화면의 리소스(~320dpi)
  • xxhpi : 초초고밀도 화면의 리소스(~480dpi)
  • xxxhdpi : 초초초고밀도 화면의 리소스(~640dpi)
  • nodpi : 화면의 픽셀 밀도와 관계없이 조정할 수 없는 리소스
  • anydpi : 어떤 밀도로도 조정 가능한 리소스

적응형 아이콘

Android 8.0(API 수준 26)부터 적응형 런처 아이콘을 지원하여 앱 아이콘이 더 유연해지고 흥미로운 시각 효과를 발휘할 수 있습니다. 개발자는 앱 아이콘을 두 레이어, 즉 포그라운드 레이어와 백그라운드 레이어로 구성할 수 있습니다.

  • 적응형 아이콘의 레이어 구조
    • 마스크
    • 포그라운드 레이어
    • 백그라운드 레이어

적응형 아이콘은 플랫폼의 API 수준 26에서 추가되었으므로 -v26 리소스 한정자가 있는 mipmap 리소스 디렉터리에서 적응형 아이콘을 선언해야 합니다. 즉, 이 디렉터리의 리소스는 API26(Android 8.0) 이상을 실행하는 기기에만 적용됩니다. 이 디렉터리의 리소스 파일은 이전 버전의 플랫폼을 실행하는 기기에서는 무시됩니다.

포그라운드 및 백그라운드 레이어 애셋 요구사항

머터리얼 - Android 아이콘 디자인 안내

포그라운드 레이어의 주요 콘텐츠가 안전 영역내에 포함되어 다양한 마스크 모양으로 인해 잘리지 않아야 합니다.

안전 영역 관련 글

적응형 아이콘 여러가지 시각효과를 포함하는 디자인

벡터 드로어블 vs 비트맵 이미지

벡터 드로어블과 비트맵 이미지는 모두 그래픽을 설명하지만 중요한 차이점이 있습니다.

비트맵 이미지각 픽셀의 색상 정보를 제외하고 보유한 이미지에 관해 잘 알지 못합니다. 반면에 벡터 그래픽이미지를 정의하는 모양을 그리는 방법을 알고 있습니다. 이러한 지침은 색상 정보와 함께 일련의 점과 선, 곡선으로 구성됩니다. 벡터 그래픽화질 저하 없이 모든 화면 밀도의 어떤 캔버스 크기로도 조정할 수 있다는 것이 장점입니다.

벡터 드로어블은 Android의 벡터 그래픽 구현으로, 휴대기기에서 충분히 유연하도록 만들어졌습니다. 이러한 가능한 요소를 사용하여 XML로 정의할 수 있습니다. 모든 밀도 버킷에 비트맵 애셋 버전을 제공하는 대신 이미지를 한 번만 정의하면 됩니다. 따라서 앱의 크기가 줄어 유지하기가 쉬워집니다.

  • Android 플랫폼에서 벡터 드로어블은 Android 5.0(API 21) 전에는 추가되지 않음.
  • 이전 버전에서 벡터 드로어블을 지원하게 하려면 gradlevectorDrawble 요소를 추가해주어야 함.
android {
	defaultConfig {
   		...
        vectorDrawables.useSupportLibrary = true
    }
    ...
}

비트맵 이미지와 비교해 벡터 드로어블을 사용하는 데는 단점이 있습니다. 예를 들어 아이콘은 단순한 모양으로 구성되기 때문에 벡터 드로어블로 적합할 수 있지만 사진은 일련의 모양으로 설명하기 어려울 수 있습니다. 이 경우 비트맵 애셋을 사용하는 것이 더 효율적입니다.

앱에 적용할 수 있는 한 가지 시각적 개선 사항은 앱 테마의 기본 색상을 기반으로 드로어블의 색조를 조정하는 것입니다.

  • android:tint 속성을 ?attr/colorPrimary로 설정하면, 밝은 테마와 어두운 테마에 설정된 colorPrimary 속성에 따라 앱 아이콘 등의 벡터 드로어블의 색이 변경되기 때문에 조금 저 일관성 있는 디자인이 될 수 있음.

drawable-anydpi-v26

적응형 아이콘에만 사용하는 리소스를 모아두는 디렉토리(새로 생성)

이 폴더 구조를 사용하면 적응형 아이콘 파일을 찾고 관리하기가 더 쉬워집니다.

  • -anydpi
    • 어떤 밀도로도 조정할 수 있는 리소스를 나타냄
  • -v26
    • 리소스 한정자
    • 이 디렉터리의 리소스는 API26(Android 8.0) 이상을 실행하는 기기에서만 적용됨

스타일

스타일은 단일 위젯 유형의 뷰 속성 값 모음입니다. 예를 들어 TextView 스타일은 글꼴 색상, 글꼴 크기, 배경색 등을 지정할 수 있습니다. 이러한 속성을 스타일로 추출하면 레이아웃의 스타일을 여러 뷰에 쉽게 적용하고 단일 위치에 유지할 수 있습니다.

res > values 디렉터리에 style.xml이라는 새 파일을 만듭니다. style.xml에서 스타일을 한 번 정의한 후에는 레이아웃의 모든 TextView에 적용할 수 있습니다. 스타일을 처음부터 정의할 수도 있지만 MDC 라이브러리의 기존 TextView 스타일에서 확장할 수 있습니다.

구성요소 스타일을 지정할 때는 일반적으로 사용하는 위젯 유형의 상위 스타일에서 확장해야 합니다. 두 가지 이유로 이와 같이 해야합니다. 첫째, 중요한 모든 기본값을 구성요소에 설정합니다. 둘째, 스타일이 계속해서 상위 스타일의 향후 변경사항을 상속합니다.

스타일 이름을 원하는 대로 지정할 수 있지만 권장되는 규칙이 있습니다. 상위 머티리얼 스타일에서 상속하는 경우 유사한 방식으로 MaterialComponents를 앱 이름(TipTime 등)으로 바꿔 스타일 이름을 지정합니다. 그러면 변경사항이 고유한 네임스페이스로 이동되어 향후 머티리얼 구성요소에 새로운 스타일이 도입될 때 충돌이 발생할 가능성이 없어집니다. 예를 들면 다음과 같습니다.

스타일 이름 Widget.TipTime.TextView가 상위 스타일 Widget.MaterialComponents.TextView에서 상속됩니다.

스타일의 이름은 상위 스타일의 이름도 반영해야 합니다.

속성을 스타일에서 지정(예: android:textSize18sp로 설정)하고 동일한 속성을 레이아웃 파일에서도 지정(예: android:textSize14sp로 설정)하는 경우 레이아웃에서 설정한 값(14sp)이 실제로 화면에 표시되는 콘텐츠에 적용됩니다.

자주 사용되는 값의 관리 효율성을 높이려면 dimens.xml 파일을 만듭니다.

이름을 지정할 수 있는 공통적인 치수를 보유하는 dimens.xml이라는 또 다른 유용한 리소스 파일을 res > values에 만들 수 있습니다. 공통적인 값을 명명된 치수로 표준화하면 앱을 더 쉽게 관리할 수 있습니다.

키 리스너

뷰에 키 리스너를 설정하는 코드는 조금 더 복잡합니다. 일반적으로 OnKeyListner에는 키 누름이 발생할 때 트리거되는 onKey() 메서드가 있습니다. onKey() 메서드는 입력 인수 세 개, 즉 뷰, 누른 키의 코드, 키 이벤트를 사용합니다. onKey() 메서드가 호출되면 handleKeyEvent() 메서드를 호출하고 뷰 및 키 코드 인수를 전달해야 합니다.

음성 안내 지원(TalkBack)

TalkBack으로 Androd 시작하기
TalkBack 사용 또는 사용 중지하기
음성 안내 지원으로 앱 탐색

Espresso

  • Android 계측 테스트(Instrument Test)에 주로 사용됨

    Espresso는 Android Studio에서 Android 프로젝트를 만들 때 이러한 프로젝트에 사용할 수 있는 라이브러리로, 이를 사용해 개발자는 코드를 통해 UI 구성요소와 상호작용할 수 있습니다.

Espresso를 사용할 때 어려운 점 중 하나는 라이브러리를 가져오지 않으면 메서드가 자동 완성되지 않는다는 점입니다. 따라서 문서를 조사하지 않으면 Espresso에서 사용 가능한 메서드를 탐색하기 어려울 수 있습니다.

Espresso 기본 사항

빌더 패턴(Builder Pattern)

빌더 패턴은 단계별 접근 방식으로 복잡한 객체를 빌드할 수 있는 프로그래밍 디자인 패턴입니다.

  • 객체의 메서드를 만들 때 수정된 객체 자신을 반환하게 해서 '.' 으로 이어서 호출할 수 있도록 하는 방식.
class Order(val orderNumber) {
	val itemList = mutableList<Item>()
    
    fun addItem(newItem: Item): Order {
    	itemList.add(newItem)
    	return this
    }
    
    fun addAll(newItems: List<Item>): Order {
    	itemList.addAll(newItems)
        return this
    }
}

fun main() {
	# 빌더 패턴을 사용하면 이런식으로 차근차근 객체를 빌드(Build)할 수 있음.
	val order = Order(1)
    				.addItem(Noodles())
                    .addItem(Vegetables())
                    .addItem(Noodles())
}

패키지(Package)

  • 패키지 이름은 마침표(.)로 구분된 여러 단어로 구성

다음 두 가지 방법으로 패키지를 사용할 수 있습니다.

  • 코드의 여러 부분별로 서로 다른 패키지를 만듭니다. 예를 들어, 개발자는 데이터 작업에 사용하는 클래스와 UI를 서로 다른 패키지로 빌드하는 클래스로 구분하는 경우가 많습니다.
  • 코드에 있는 다른 패키지의 코드를 사용합니다. 다른 패키지의 클래스를 사용하뎌면 빌드 시스템의 종속 항목에 클래스를 정의해야 합니다. 또한 정규화된 이름(예: android.widget.TextView) 대신 축약 이름(예: TextView)을 사용할 수 있도록 클래스를 코드에 import하는 것도 표준 관행입니다.

앱의 클래스가 많지 않더라도 패키지를 사용하여 기능별로 클래스를 그룹화하는 것이 좋습니다.

패키지 이름

패키지 이름은 전역적으로 고유하기만 하다면 어떤 이름이든 사용할 수 있습니다. 위치에 관계없이 게시된 다른 패키지의 이름이 같을 수는 없습니다. 패키지가 너무 많아서 임의의 고유한 이름을 고안하기가 어렵기 때문에 프로그래머는 패키지 이름을 더 쉽게 만들고 이해할 수 있도록 이름 지정 규칙을 사용합니다.

이름 지정 규칙

  • 일반적 -> 구체적인 순서로 구성
  • 각 부분을 소문자로 표기하고 마침표로 구분
    • 마침표는 이름의 일부일 뿐이며 코드 내의 계층 구조를 나타내거나 폴더 구조를 지시하지 않음.
  • 이름 첫 부분에 개발자의 도메인이나 비즈니스의 도메인을 사용
  • 패키지 이름을 통해 패키지에 포함된 내용 및 패키지 간의 관계를 표시
    • 패키지 이름이 패키지의 계층 구조를 만들지는 않지만, 콘텐츠의 관계와 구성을 나타내기 위해 이름의 일부를 재사용

일반적인 이름

  • model : 데이터를 모델링하거나 표현하는 클래스의 패키지 이름으로 model을 사용하는 경우가 많음.

RecyclerView

  • Item - 표시할 목록의 단일 데이터 항목
  • Adapter - RecyclerView에 표시할 수 있도록 데이터를 가져와 준비하는 역할
  • ViewHolder - Item을 표시하기 위해 사용하거나 재사용할 RecyclerView용 View의 pool
  • RecyclerView - 화면에 표시되는 뷰
  • 항목 정렬 지정 : app:layoutManager="LinearLayoutManager"
  • 세로로 스크롤 가능 : android:scrollbars="vertical"
  • RecyclerView의 각 항목에는 고유한 레이아웃이 있으며, 이 레이아웃은 별도의 레이아웃 파일에서 정의
  • recyclerView.setHasFixedSize(true)
    • 성능 개선을 위한 코드.
    • 내용을 변경해도 RecyclerView의 레이아웃 크기가 변경되지 않는다는 것을 아는 경우에 사용.

Adapter

데이터를 RecylcerView에서 사용할 수 있는 형식으로 조정하는 설계 패턴

  • RecyclerView.Adapter<ViewHolder>를 상속받아야 함.

Adapter가 구현해야 하는 것

  • ViewHolder
  • 추상 메서드 getItemCount()
    • getItemCount()는 dataset의 크기를 반환해야 함.
  • 추상 메서드 onCreateViewHolder()
    • 재사용할 수 있는 기존 ViewHolder가 없는 경우 새 ViewHolder를 만들기 위해 LayoutManager가 호출하는 메서드.
    • 매개변수 parentcontext로 부터 LayoutInflator를 가져와서 inflateView에대한 ViewHolder를 반환해주어야 함.
  • 추상 메서드 onBindViewHolder()
    • List의 Item View의 내용을 바꾸기 위해 LayoutManager가 호출하는 메서드

ViewHolder

RecyclerView의 단일 항목 뷰를 나타내며 가능한 경우 재사용할 수 있는 객체

  • RecylcerView에 표시되는 List의 Item에 대한 레이아웃에 있는 개별 View에 대한 참조를 보유함. (이름이 "ViewHolder"인 이유)
  • RecyclerView가 화면에서 뷰를 효율적으로 이동하기 위해 사용하는 정도보 추가

FrameLayout

단일 하위 뷰를 보유하는데 사용하는 더 간단한 ViewGroup

LinearLayout

모든 하위 뷰를 세로 또는 가로의 단일 방향으로 정렬하는 ViewGroup

LayoutManager

Android 프레임워크에서 항목 정렬의 처리를 담당

LinearLayoutManager

1차원 리스트 형태로 item을 배치

GridLayoutManager

2차원 그리드 형태로 item을 배치.

  • app:spanCount 속성을 변경해서 열 개수를 조절할 수 있음.

리소스 주석(Resource Annotation)

클래스 생성자나 메서드의 매개변수 앞에 붙여서 해당 매개변수가 어떤 리소스를 가져와야 하는지를 나타내는 주석. 잘못된 유형의 리소스 ID를 제공하면 경고가 표시됨.

카드 뷰(Card View)

Card View를 사용하면 컨테이너 스타일을 일관되게 유지하면서 간편하게 뷰 그룹을 포함할 수 있습니다.

카드에 관한 가이드

Kotlin 정렬

정렬하기 위해 두 객체를 비교할 때 규칙은 첫 번째 객체가 두 번째 객체보다 작으면 0보다 작은 값을 반환하고 첫 번째 객체가 두 번째 객체보다 크면 0보다 큰 값을 반환하는 것입니다.

  • (첫 번째 값 - 두 번째 값)이 반환된다고 생각하면 쉬움.

SAM(Single Abstract Method, 단일 추상 메서드) 변환

// Long Form
calculateButton.setOnClickListener(object: View.OnClickListener {
	overrdie fun onClick(view: View?) {
    	calculateTip()
    }
})

// Short Form
calculateButton.setOnClickListener { view -> calculateTip() }

람다에 OnClickListeneronClick() 메서드와 동일한 함수 유형이 있는 경우를 관찰합니다(View 인수 하나를 사용하고 반환 값이 없음을 나타내는 Unit을 반환함).

Kotlin의 단일 추상 메서드(SAM) 변환 때문에 축약 버전의 코드가 가능합니다. Kotlin은 람다를 단일 추상 메서드 onClick()을 구현하는 OnClickListener 객체로 변환합니다. 람다의 함수 유형이 추상 함수 유형과 일치하는 지 확인하면 됩니다.

설명

SAM 변환이란, 인터페이스에 추상 메서드가 하나 뿐일 때, 이 인터페이스의 구현을 그것이 가지고 있는 추상 메서드와 동일한 함수 타입의 함수로 대신하는 것.

참고 : https://beomseok95.tistory.com/92

인텐트(Intent)

인텐트는 실행할 작업을 나타내는 객체입니다.

  • 실행 결과가 아닌, 요청을 묘사함
  • 모든 Activity는 해당 Activity를 실행하는데 사용된 인텐트의 참조를 가지고 있음. (intent 속성)
    • Acitivity가 intent로부터 실행된 것이 아니라면, intent 속성은 null 값을 가짐.

명시적 인텐트(Explicit intent)

  • 구체적, 실행할 Activity를 정확히 명시
  • 실행해야할 Activity를 명확히 알고 있을 때 사용
  • 주로 자체 앱에서 사용
  • 명시적 인텐트를 사용할 때 인자로 전달한 실제 Activity 객체는 백그라운드에서 만들어짐.

암시적 인텐트(Implicit intent)

  • 추상적, 실행할 작업 유형을 알려줌.
  • 주로 다른 앱에서 해당 작업을 실행할 때 사용

인텐트 유형

암시적 인텐트를 사용할 때 Intent의 첫 번째 인자로 전달하는 것. Intent.xxx 형태

  • ACTION_VIEW : URI를 사용하는 일반적인 인텐트
  • ACTION_SET_ALAM : 백그라운드에서 알람을 설정
  • ACTION_DIAL : 전화를 검
  • CATEGORY_APP_MAPS : 지도 앱을 실행
  • CATEGORY_APP_EMAIL : 이메일 앱을 실행
  • CATEGORY_APP_GALLERY : 갤러리(사진) 앱을 실행
  • 등등

흔히 사용되는 인텐트(Common Intents)

인텐트 및 인텐트 필터

Extra

  • 인텐트의 명령어 집합
  • putExtra에서 첫 번째 인자로 전달한 이름을 통해 intent를 받은 쪽에서 그 데이터를 검색할 수 있음.
    • Extra의 이름이 될 첫 번째 인자에, companion object로 상수를 선언해서 사용하는 것이 좋다.

URI(Uniform Resource Identifier)

URL와 URN으로 나누어짐.

URL(Uniform Resource Locator)

  • 웹 페이지를 가리키는 문자열
    • https://developer.android.com
    • mailto:someone@gmail.com
    • 등등

URN(Uniform Resource Name)

  • URI 중 URL이 아닌 것들
    • 전화번호의 주소 - tel:1-555-867-5309
    • 등등

앱 바

앱을 실행하면 상단에 나타나는 바.
앱 이름 표시 뿐만 아니라 바로가기나 더 보기 메뉴 등을 담을 수 있음.

XML로 옵션 메뉴 만들기

현재 프래그먼트의 기능에 따라 더욱 관련성이 높은 제목을 제공하는 것이 더 나은 사용자 환경입니다.

Activity Lifecycle(수명주기)

Activity Lifecycle은 Activity의 전체 기간 중 일련의 Activity 상태입니다. 수명 주기는 Activity가 생성되는 시점에 시작하여 Activity가 소멸되어 시스템에서 Activity 리소스가 회수될 때까지 이어집니다.

Android 개발자는 Activity 수명 주기를 파악해야 합니다. Activity가 수명 주기 상태 변경에 올바르게 응답하지 않으면 앱에 이상한 버그가 발생하여 사용자가 동작을 혼동하거나 앱에서 Android 시스템 리소스를 너무 많이 사용할 수 있습니다. Android 수명 주기를 파악하고 수명 주기 상태 변경에 올바르게 응답하는 것은 좋은 Android 개발자가 되기 위한 중요한 요소입니다.

동작을 변경하거나 Activity 수명 주기 상태가 변경될 때 코드를 실행하려고 할 때가 많습니다. 따라서 Actvity 클래스 자체와 Activity의 모든 서브 클래스(예: AppCompatActivity)는 일련의 수명 주기 콜백 메서드를 구현합니다. Android에서는 Activity가 한 상태에서 다른 상태로 이동할 때 이러한 콜백을 호출하고 개발자는 이러한 메서드를 자체 Activity에서 재저으이하여 수명 주기 상태 변경에 응답해 작업을 실행할 수 있습니다.

수명 주기 관련 codelab

onCreate() 메서드를 재정의할 때 슈퍼클래스 구현을 호출하여 Activity 생성을 완료해야 하므로 Acitivity 내에서 super.onCreate()를 즉시 호출해야 합니다. 다른 수명 주기 콜백 메서드의 경우에도 마찬가지입니다.

Activity는 코드에서 수동으로 Activity의 finish() 메서드를 호출하거나 사용자가 앱을 강제 종료하는 경우에도 완전히 종료될 수 있습니다. 예를 들어 사용자는 최근 화면에서 앱을 강제 종료하거나 닫을 수 있습니다. Androd 시스템은 앱이 오랫동안 화면에 표시되지 않으면 자체적으로 Activity를 종료할 수도 있습니다. Android는 배터리를 보존하고 앱의 리소스를 다른 앱에서 사용할 수 있도록 이 작업을 실행합니다.

Activity는 사용자가 Activity에서 벗어날 때마다 완전히 닫히지 않습니다.

  • Activity가 화면에 더 이상 표시되지 않으면 이는 Activity가 백그라운드에 배치되는 것입니다. 이와 반대의 경우는 Activity가 포그라운드에 있거나 화면에 표시되는 것입니다.
  • 사용자가 앱으로 돌아오면 동일한 Acitivity가 다시 시작되어 화면에 다시 표시됩니다. 수명 주기에서 이 부분을 앱의 표시 수명 주기라고 합니다.

앱이 다시 시작되고 onResume()이 호출되면 앱은 사용자 포커스를 확보합니다. 즉, 사용자가 앱과 상호작용할 수 있습니다. 앱이 완전히 화면에 표시되고 사용자 포커스를 보유하는 수명 주기 부분은 대화형 수명 주기라고 합니다.

onCreate()

  • Initialized -> Created 로 상태를 변경하는 수명 주기 메서드
  • 앱을 만듦.
  • Activity가 초기화 된 직후(새 Activity 객체가 메모리에 만들어질 때) 한 번만 호출
  • Activity의 일회성 초기화를 실행함.
    • 레이아웃 확장, 클릭 리스너 정의, 뷰 결합 설정 등

onStart()

  • Created -> Started 로 상태를 변경하는 수명 주기 메서드
  • Activity를 시작하고 화면에 표시되게 함.
  • onStart()가 호출되면 Activity가 화면에 표시됨.
    • Started 상태부터 보이는(visible) 상태가 됨.
  • Activity 수명 주기에서 여러 번 호출될 수 있음.

onRestart()

  • Created -> Started 로 상태를 변경하는 수명 주기 메서드
  • Activity를 시작하고 화면에 표시되게 함.
  • onRestart()onStop() 이후 Activity가 다시 화면에 표시될 때(예: 홈 화면으로 갔다가 돌아올 때) 실행됨.
  • onRestart() 실행 후에 onStart()도 함께 실행 됨.
  • Activity가 처음으로 시작되지 않은 경우에만 호출하려는 코드를 배치할 때 사용

onResume()

  • Started -> Resumed 로 상태를 변경하는 수명 주기 메서드
  • Activity 포커스를 제공하고 사용자가 상호작용할 수 있도록 Activity를 준비함.
  • Activity 수명 주기에서 여러 번 호출될 수 있음.

onPause()

  • Resumed -> Started 로 상태를 변경하는 수명 주기 메서드
  • Activity 수명 주기에서 여러 번 호출될 수 있음.
  • onPause() 호출 시 앱에 더 이상 포커스가 없음.
  • 앱이 백그라운드로 전환될 때 호출
  • onPause()에서 실행되는 모든 코드는 다른 항목이 표시되는 것을 차단하므로 onPause()의 코드는 가볍게 유지하는 것이 좋음.
    • 전화가 왔을 때, onPause()가 호출되는데, onPause()가 너무 무거우면 수신 전화 알림을 지연시켜 문제가 될 수 있음.

onStop()

  • Started -> Created 로 상태를 변경하는 수명 주기 메서드
  • 앱을 시작한 후 기기 홈 화면으로 돌아오면 Activity가 중지되고 더 이상 화면에 표시되지 않음.
  • Activity 수명 주기에서 여러 번 호출될 수 있음.
  • onStop() 이후에는 앱이 더 이상 화면에 표시되지 않음.
  • 앱이 중지되었지만, Activity 객체는 여전히 백그라운드 메모리에 있는 상태가 됨.
  • 앱이 백그라운드로 전환될 때 호출

onDestroy()

  • Created -> Destroyed 로 상태를 변경하는 수명 주기 메서드
  • 앱에서 사용하는 리소스를 정리할 때 한 번만 호출
  • onDestroy()의 실행은 Activity가 완전히 종료되었으며 가비지 컬렉션될 수 있음을 의미함.(호출 이후 시스템이 메모리 정리를 시작함)

포커스와 가시성

포커스와 가시성의 차이가 중요한 이유는 Activity가 화면에 부분적으로 표시되지만 사용자 포커스는 없을 수 있기 때문입니다.

onPause()만 사용한 중단은 보통 Activity로 돌아가거나 다른 Activity 또는 앱으로 이동하기 전에 잠시 지속됩니다. 일반적으로 UI를 계속 업데이트하여 나머지 앱이 멈춘 것처럼 보이지 않도록 하는 것이 좋습니다.

구성 변경(Configuration Change)

구성 변경은 기기 상태가 매우 급격하게 변경되어 시스템이 변경사항을 확인하는 가장 쉬운 방법이 활동을 완전히 종료하고 다시 빌드하는 것일 때 발생합니다.

  • 사용자가 기기 언어를 변경하면 다른 텍스트 방향과 문자열 길이를 수용하도록 전체 레이아웃을 변경해야 할 수 있습니다.
  • 사용자가 기기를 도크에 연결하거나 물리적 키보드를 추가하면 앱 레이아웃은 다른 디스플레이 크기나 레이아웃을 활용해야 할 수 있습니다.
  • 기기 방향이 변경되면(기기가 세로 모드에서 가로 모드 또는 이와 반대로 회전하는 경우) 새 방향에 맞게 레이아웃을 변경해야 할 수 있습니다.

구성 변경이 발생하면 Android는 모든 Activity 수명 주기의 종료 콜백을 호출합니다. 그런 다음 Android는 처음부터 Activity를 다시 시작하여 모든 수명 주기 시작 콜백을 실행합니다.

onSaveInstanceState()

  • Activity가 소멸되면 필요할 수 있는 데이터를 저장하는 데 사용하는 콜백
  • Started -> Created 로 상태가 변하는 과정에서 onStop() 호출 이후에 호출됨.
    • Activity가 중지된 수, 앱이 백그라운드로 전활될 때마다 호출됨.
  • onSaveInstanceState() 재정의는 두 가지가 있음.
    • outState 매개변수만 있는 경우
    • outState 매개변수와 outPersistentState 매개변수가 있는 경우

onRestoreInstanceState(Bundle)

  • Created -> Started 로 상태 변화하는 과정에서 onStart() 호출 이후에 호출됨.
  • onSaveInstanceState() 메서드에서 채워진 BundleonCreate(Bundle)onRestoreInstanceState(Bundle) 두 수명 주기 메서드에 모두 전달됨.
  • 대부분의 경우 onCreate()에서 Activity 상태를 복원하지만, onCreate()가 호출된 후 일부 상태를 복원해야 할 때 onRestoreInstanceState(Bundle)을 사용하면 됨.

Bundle

Bundle은 키-값 쌍 모음으로, 키가 항상 문자열입니다. IntBoolean 값과 같은 간단한 데이터를 번들에 넣을 수 있습니다.
시스템이 이 번들을 메모리에 유지하므로 번들의 데이터를 작게 유지하는 것이 좋습니다. 이 번들의 크기도 제한되지만 기기마다 크기는 다릅니다. 너무 많은 데이터를 저장하면 TransactionTooLargeException 오류로 인해 앱이 비정상 종료될 수 있습니다.

putInt() 메서드와 putFloat()putString()과 같은 Bundle 클래스의 유사한 메서드는 두 가지 인수를 사용합니다. 키 문자열과 저장할 실제 값입니다.

getInt() 메서드는 두 가지 인수를 사용합니다.

  • 키 역할을 하는 문자열
  • 번들의 키에 값이 없는 경우를 위한 기본 값
  • onSaveInstanceState()onCreate() 또는 onRestoreInstanceState()에서 동일한 키 값을 사용해야 하므로 키는 클래스 외부에 컴파일 타임 상수(const val)로 선언하는 것이 좋음.

앱이 백그라운드로 전환되면 onStop()이 호출된 직후 앱 데이터를 번들에 저장할 수 있습니다. EditText의 콘텐츠와 같은 일부 앱 데이터는 자동으로 저장됩니다.

AppCompatActivity

새로운 버전의 안드로이드 기능을 구 버전의 디바이스에서 사용할 수 있도록 하기 위한 Activity의 Base class 정도로 이해하면 될듯.

자세한 내용은 AppCompatActivity 참조.

AppCompatActivity의 매개변수화된 생성자

둘은 같은 코드

class MainActivity : AppCompatActivity(R.layout.activity_main)
class MainActivity : AppCompatActivity() {
	
    override fun onCreate(savedInstanceState: Bundle?) {
    	super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

프래그먼트(Fragment)

프래그먼트는 간단하게 마래 앱의 사용자 인터페이스에서 재사용 가능한 부분입니다.

  • Activity와 유사
    • 수명 주기가 있음
    • 사용자 입력에 응답할 수 있음
  • Activity가 화면에 표시될 때 뷰 계층 구조 내에 항상 포함됨
  • 재사용성과 모듈성을 강조
    • 단일 Activity에서 여러 프래그먼트를 동시에 호스팅할 수도 있음

프래그먼트의 수명주기

  • Lifecycle.State 열거형(enum type)으로 표현되는 다섯 가지 상태
    • INITIALIZED : 프래그먼트의 새 인스턴스가 인스턴스화됨.
    • CREATED : 첫 번째 프래그먼트 수명 주기 메서드가 호출됨. 프래그먼트와 연결된 뷰가 만들어짐.
    • STARTED : 프래그먼트가 화면에 표시되지만 포커스가 없으므로 사용자 입력에 응답할 수 없음.
    • RESUMED : 프래그먼트가 표시되고 포커스가 있음.
    • DESTROYED : 프래그먼트 객체의 인스턴스화가 취소됨.
  • Activity의 수명주기와의 차이점
    • CREATED 상태와 연관된 메서드가 몇개 추가됨.

onCreate()

  • 프래그먼트가 인스턴스화되었고 CREATED 상태임.
  • 아직 상응하는 뷰가 만들어지지 않음.

onCreateView()

  • 레이아웃을 확장하는 곳.
  • 프래그먼트가 CREATED 상태로 전환됨.

onViewCreated()

  • 뷰가 만들어진 후 호출됨.
  • 일반적으로 findViewById()를 호출해서 특정 뷰를 속성에 바인딩하는 곳.

onStrat()

  • 프래그먼트가 STARTED 상태로 전환됨.

onResume()

  • 프래그먼트가 RESUMED 상태로 전환됨.
  • 포커스를 보유함.(사용자의 입력에 응답할 수 있음)

onPause()

  • 프래그먼트가 STARTED 상태로 다시 전환됨.
  • UI가 아직 사용자에게 표시됨.

onStop()

  • 프래그먼트가 CREATED 상태로 전환됨.
  • 객체가 인스턴스화된 상태임.
  • 화면에 표시되지는 않음.

onDetroyView()

  • 프래그먼트가 DESTROYED 상태로 전환되기 직전에 호출됨.
  • 뷰는 메모리에서 삭제됨.
  • 프래그먼트 객체는 여전히 있음.

onDestroy()

  • 프래그먼트가 DESTROYED 상태로 전환됨.

프래그먼트와 뷰 바인딩

프래그먼트에 대한 뷰 바인딩 참조는 Nullable 타입이고, 초기값은 null이어야 함.

  • onCreateView()가 호출될 때까지 레이아웃을 확장할 수 없기 때문.

onDetached()

  • 상응하는 액티비티와 프래그먼트가 소멸될 때 호출되는 콜백 메서드

get() 속성

private val binding get() = _binding!!

여기서 get()은 이 속성이 'get-only'임을 나타냅니다. 즉, 값을 가져올 수 있지만 여기서와 같이 할당되고 나면 다른 것에 할당될 수 없습니다.

Navigation Component

Navigation graph는 앱에서 Navigation을 시각적으로 보여주는 XML 파일입니다. 파일은 개별 Activity 및 Fragment에 상응하는 Destination과 한 Destination에서 다른 Destination으로 이동하려고 코드에서 사용할 수 있는 Destination 사이의 Action으로 구성됩니다. 레이아웃 파일과 마찬가지로 Android 스튜디오는 Navigation graph에 Destination과 Action을 추가하는 시각적 편집기를 제공합니다.

백그라운드에서는 실제로 NavGraph의 새 인스턴스가 생성됩니다. 그러나 Navigation graph의 Destination은 FragmentContainerView로 사용자에게 표시됩니다. XML 파일을 만들고 가능한 Destination을 정의하기만 하면 됩니다. 그런 다음 생성된 코드를 사용하여 프래그먼트 간에 이동할 수 있습니다.

NavHost는 활동 내에서 Navigation graph의 Destination을 표시하는 데 사용됩니다. Fragment간에 이동하면 NavHost에 표시되는 Destination이 업데이트됩니다. MainActivity에서 NavHostFragment라는 기본 제공 구현을 사용합니다.

NavController 객체를 사용하면 NavHost에 표시되는 Destination 간 탐색을 제어할 수 있습니다. 인텐트를 사용할 때는 startActivity를 호출하여 새 화면으로 이동해야 했습니다. Navigation Component를 사용하면 NavControllernavigate() 메서드를 호출하여 표시되는 Fragment로 교체할 수 있습니다. NavController를 사용하면 시스템의 UP 버튼에 응답하여 이전에 표시된 Fragment로 다시 이동하는 것과 같은 일반적인 작업을 처리할 수도 있습니다.

Safe Args 플러그인

프래그먼트 간에 데이터를 전달할 때 type safe를 지원하는 Gradle 플러그인

Short-circuit evaluation(단락 평가)

override fun onSupportNavigateUp(): Boolean {
	return navController.navigateUp() || super.onSupportNavigateUp()
}
  • 위의 코드는 navController.navigateUp() 함수가 false를 반환할 경우에만 super.onSupportNavigateUp() 함수를 호출함.
  • 위의 코드 처럼 || 연산자는 둘 중 하나만 true이면 되므로, 왼쪽이 false일 경우에만 오른쪽의 문장을 평가함. 이를 Short-circuit evalutaion이라고 함.

아키텍처(Architecture)

앱 아키텍처는 일련의 디자인 규칙입니다. 아키텍처는 주택의 청사진과 마찬가지로 앱의 구조를 제시합니다. 훌륭한 햅 아키텍처를 사용하면 유연하고 확장 가능하며 향후 유지관리가 가능한 강력한 코드를 만들 수 있습니다.

아키텍처는 앱에서 클래스 간의 책임을 할당하는 가이드라인을 제공합니다. 앱 아키텍처가 잘 디자인되어 있으면 향후 앱을 확장하고 더 많은 기능을 포함할 수 있습니다. 또한 팀 공동작업도 더 간편합니다.

Android 아키텍처의 기본 클래스 또는 구성요소는 UI 컨트롤러(Activity/Fragment), ViewModel, LiveData, Room입니다. 이러한 구성요소는 수명 주기의 복잡성을 어느 정도 처리하므로 수명 주기 관련 문제를 피하는 데 도움이 됩니다.

Android Architecture Components
앱 아키텍처 가이드

  • 일반적인 아키텍처 원칙
    • 관심사 분리
    • 모델에서 UI 만들기

관심사 분리(Seperation of concerns)

관심사 분리 디자인 원칙은 각각 별개의 책임이 있는 여러 클래스로 앱을 나눠야 한다는 원칙입니다.

  • 단일 책임 원칙(Single Responsibility Principle, SRP)

모델에서 UI 만들기(Drive UI from a model)

또 하나의 중요한 원칙은 모델에서 UI를 만들어야 한다는 것입니다. 가급적 지속적인 모델을 권장합니다. 모델은 앱의 데이터 처리를 담당하는 구성요소로, 앱의 View 객체 및 앱 구성요소와 독립되어 있으므로 앱의 수명 주기 및 관련 문제의 영향을 받지 않습니다.

UI 컨트롤러(Activity/Fragment)

액티비티와 프래그먼트는 UI 컨트롤러입니다. UI 컨트롤러는 화면에 뷰를 그리고 사용자 이벤트나 사용자가 상호작용하는 다른 모든 UI 관련 동작을 캡처하여 UI를 제어합니다. 앱의 데이터 또는 데이터에 관한 모든 의사 결정 로직은 UI 컨트롤러 클래스에 포함되어서는 안 됩니다.

Android 시스템은 특정 사용자 상호작용을 기반으로 또는 메모리 부족과 같은 시스템 조건으로 인해 언제든지 UI 컨트롤러를 제거할 수 있습니다. 이러한 이벤트는 개발자가 직접 제어할 수 없기 때문에, UI 컨트롤러에 앱 데이터나 상태를 저장해서는 안 됩니다. 대신 데이터에 관한 의사 결정 로직을 ViewModel에 추가해야 합니다.

ViewModel

ViewModel은 뷰에 표시되는 앱 데이터의 모델입니다. 모델은 앱의 데이터 처리를 담당하는 구성요소로, 아키텍처 원칙에 따라 모델에서 UI가 도출 되는 앱을 만들 수 있습니다.

ViewModel은 Android 프레임워크에서 액티비티나 프래그먼트가 소멸되고 다시 생성될 때 폐기되지 않는 앱 관련 데이터를 저장합니다. ViewModel 객체는 구성이 변경되는 동안 자동으로 유지되어(액티비티 또는 프래그먼트 인스턴스처럼 소멸되지 않음) 보유하고 있는 데이터가 다음 액티비티 또는 프래그먼트 인스턴스에서 즉시 사용될 수 있습니다.

앱에 ViewModel을 구현하려면 아키텍처 구성요소 라이브러리에서 가져온 ViewModel 클래스를 확장하고 이 클래스 내에 앱 데이터를 저장합니다.

  • ViewModel 데이터는 public 변수로 노출하지 않는 것이 좋음.
    • 앱 데이터가 외부 클래스에 의해 예상치 못한 방식으로 수정되는 것을 방지.
    • 대신 지원 속성(backing property)를 구현하고, 필요한 경우 각 속성의 변경 불가능한 public 버전을 노출하는 것이 좋음.
  • ViewModelmodel 패키지로 분리하여 UI 코드와 분리.

ViewModel의 수명 주기

프레임워크는 액티비티나 프래그먼트의 범위(Scope)가 유지되는 동안 ViewModel을 유지합니다. ViewModel은 소유자가 화면 회전과 같은 구성 변경으로 인해 소멸되는 경우에도 소멸되지 않습니다. 소유자의 새 인스턴스는 기존 ViewModel 인스턴스에 다시 연결됩니다.

ViewModel은 연결된 프래그먼트가 분리되거나 액티비티가 완료되면 소멸됩니다. ViewModel이 소멸되기 직전에 onCleared() 콜백이 호출됩니다.

요약

프래그먼트/액티비티(UI 컨트롤러)의 책임ViewModel의 책임
액티비티 및 프래그먼트는 뷰와 데이터를 화면에 그리고 사용자 이벤트에 응답합니다.ViewModel은 UI에 필요한 모든 데이터를 보유하고 처리합니다. 뷰 계층 구조(예: 뷰 결합 객체)에 액세스하거나 액티비티 또는 프래그먼트의 참조를 보유해서는 안됩니다.

공유 ViewModel(Shared ViewModel)

공유 ViewModel을 사용하여 햅의 데이터를 단일 ViewModel에 저장합니다. 앱의 여러 프래그먼트는 activity scope을 사용하여 공유 ViewModel에 액세스합니다.

대부분의 프로덕션 앱에서 프래그먼트 간에 데이터를 공유하는 것은 일반적인 사용 사례(use case)입니다.

  • 공유 ViewModel에서는 viewModels() 대리자 클래스 대신 activityViewModels()을 사용.
    • viewModels()는 현재 프래그먼트로 범위(scope)가 지정된 ViewModel 인스턴스 제공. 인스턴스가 프래그먼트마다 달라짐.
    • activityViewModels()는 현재 액티비티으로 범위가 지정된 ViewModel 인스턴스를 제공. 동일한 액티비티의 여러 프래그먼트 간에 인스턴스가 동일하게 유지됨.

LiveData

LiveData 클래스는 Android Architecture Compoenent의 일부이기도 하며 Observed한 데이터 홀더 클래스입니다.

LiveData는 수명 주기를 인식하는 Observable인 데이터 홀더 클래스입니다.

LiveData의 특성은 다음과 같습니다.

  • LiveData는 데이터를 보유(hold)합니다. LiveData는 모든 유형의 데이터에 사용할 수 있는 래퍼입니다.
  • LiveData는 Observable입니다. 즉, LiveData 객체에서 보유한 데이터가 변경되면 Observer에 알림이 제공됩니다.
  • LiveData는 수명 주기를 인식합니다. LiveData에 Observer를 연결하면 Observer는 LifecycleOwner(일반적으로 액티비티 또는 프래그먼트)와 연결됩니다. LiveDataSTARTED 또는 RESUMED 같은 활성 수명 주기 상태인 Observer만 업데이트합니다.

LiveData 및 Observer에 대한 내용

LiveData 관찰자 api

MutableLiveData

MutableLiveData는 변경 가능한 버전의 LiveData입니다. 즉, 내부에 저장된 데이터의 값을 변경할 수 있습니다.

  • LiveData / MutableLiveData는 Generic 클래스.
  • LiveData / MutableLiveData 객체의 값은 동일하게 유지되고 이 객체에 저장된 데이터만 변경됨.
  • LiveData 객체 내의 데이터에 액세스하려면 value 프로퍼티 사용

ViewLifecycleOwner

  • LiveDataobserve() 함수에 사용하는 Parameter.
  • ViewLifecycleOwner는 현재 View의 수명 주기를 나타냄?
    • LiveData 가 현재 View의 수명 주기를 인식하고, 이 View가 활성 상태(STARTED, RESUMED) 일 때만 Observer에 알릴 수 있음.

데이터 결합(Data binding)

  • Android Jetpack 라이브러리의 일부
  • 레이아웃의 데이터 변경 사항을 코드에서 수신 가능하게 함.

데이터 결합을 사용하면 Observable인 LiveData 값이 변경될 때 바인딩된 레이아웃의 UI 요소에도 알림이 전송되며 레이아웃 내에서 UI를 업데이트할 수 있습니다.

간단히 말해서 데이터 결합은 코드에서 데이터를 뷰 + 뷰 결합에 결합(뷰를 코드에 결합)하는 것입니다.

  • 액티비티에서 많은 UI 프레임워크 호출을 삭제할 수 있어 파일이 더욱 단순해지고 더 손쉬운 유지 관리가 가능
  • 앱 성능이 향상되며 메모리 누수 및 null pointer exception을 방지

데이터 결합
양방향 데이터 결합

결합 표현식(binding expression)

결합 표현식은 레이아웃 내에서 레이아웃 속성을 참조하는 속성(attribute properties)(예: android:text)에서 작성됩니다. 레이아웃 속성은 <variable> 태그를 통해 데이터 결합 레이아웃 파일의 상단에서 선언됩니다. 종속 변수 중 하나라도 변경되면 'DB 라이브러리`가 결합 표현식을 실행하고 이에 따라 뷰를 업데이트 합니다. 이러한 변경 감지는 데이터 결합 라이브러리를 사용할 때 무료로 제공되는 훌륭한 최적화 기능입니다.

  • 결합 표현식의 구문
    • @로 시작하고 중괄호 {}로 래핑

Kotlin 속성 위임(Property Delegation)

Kotlin에 는 각 변경 가능한(var) 속성에 자동으로 생성된 기본 getter 함수와 setter 함수가 있습니다. 값을 할당하거나 속성 값을 읽을 때 setter 및 getter 함수가 호출됩니다.

읽기 전용 속성(val)의 경우 변경 가능한 속성과 조금 다릅니다. 기본적으로 getter 함수만 생성됩니다. 읽기 전용 속성의 값을 읽을 때 이 getter 함수가 호출됩니다.

Kotlin에서 속성 위임을 사용하면 getter-setter 책임을 다른 클래스에 넘길 수 있습니다.
이 클래스(대리자 클래스라고 함)는 속성의 getter 및 setter 함수를 제공하고 변경사항을 처리합니다.

대리자 속성은 다음과 같이 by 절 및 대리자 클래스 인스턴스를 사용하여 정의됩니다.

// Syntax for property delegation
var <property-name> : <property-type> by <delegate-class>()

속성 위임 방식을 사용해 viewModel 객체의 책임을 viewModels라는 별도의 클래스에 위임합니다. 즉, viewModel 객체에 액세스하면 이 객체는 대리자 클래스 viewModels에 의해 내부적으로 처리됩니다. 대리자 클래스는 첫 번째 액세스 시 자동으로 viewModel 객체를 만들고 이 값을 구성 변경 중에도 유지했다가 요청이 있을 때 반환합니다.

Kotlin 지원 속성(Backing Property)

지원 속성을 사용하면 정확한 객체가 아닌 getter에서 무언가를 반환할 수 있습니다.

getter 메서드와 setter 메서드 중 하나 또는 둘 모두를 재정의하여 고유한 맞춤 동작을 제공할 수 있습니다. 지원 속성을 구현하려면 읽기 전용 버전의 데이터를 반환하도록 하는 getter 메서드를 재정의합니다.

// 선언된 클래스에서만 변경이 가능하도록 private var로 선언
private var _count = 0

// 어디서든 접근이 가능하지만 수정은 불가능하도록 val로 선언 후 getter를 재정의(override).
// count에 접근하면 get() 함수가 호출되고, _count의 값이 반환됨.
val count: Int
	get() = _count

경고 : viewModel의 변경 가능한 필드(멤버 변수)를 외부로 노출하지 마세요. 다른 클래스에서 수정되지 않도록 해야 합니다. ViewModel 내의 변경 가능한 데이터는 반드시 private이어야 합니다.

지원 속성의 이름 규칙

private 속성 앞에 밑줄(_)을 붙이는 것

Kotlin init

Kotlin은 객체 인스턴스 초기화 중에 필요한 초기 설정 코드를 배치하는 장소로 이니셜라이저 블록(init 블록이라고도 함)을 제공합니다. 이니셜라이저 블록에는 init 키워드 뒤에 중괄호 {}가 붙습니다. 이 코드 블록은 객체 인스턴스가 처음 생성되어 초기화 될 때 실행됩니다.

대화상자(Dialogs)

대화상자는 사용자에게 결정을 내리거나 추가 정보를 입력하라는 메시지를 표시하는 작은 창(화면)입니다.

  • 일반적으로 전체 화면을 가득 채우지 않음.
  • 사용자가 조치를 취해야 계속 진행할 수 있음.

Context

이름에서 알 수 있듯이 Context는 애플리케이션이나 액티비티, 프래그먼트의 컨텍스트나 현재 상태를 나타냅니다.

  • 액티비티, 프래그먼트, 애플리케이션과 관련된 정보를 포함
  • 일반적으로 리소스, 데이터베이스, 기타 시스템 서비스에 액세스하는 데 사용됩니다.

SpannableString

SpannableString은 추가 정보가 연결된 문자열입니다.

RESTful

오늘날 대부분의 웹 서버는 REST(REpresentational State Transfer의 약자)라는 일반적인 스테이트리스(Stateless) 웹 아키텍처를 사용해 웹 서비스를 실행합니다. 이 아키텍처를 제공하는 웹 서비스를 RESTful 서비스라고 합니다.

Android Gradle 종속 항목

Android Gradle을 사용하면 외부 라이브러리를 프로젝트에 추가할 수 있습니다. 라이브러리 종속 항목 외에도 라이브러리가 호스팅 되는 저장소(repository)도 포함해야 합니다. Jetpack 라이브러리의 ViewModelLiveData와 같은 Google 라이브러리는 Google 저장소에 호스팅됩니다. Retrofit과 같은 대부분의 커뮤니티 라이브러리는 JCenter에서 호스팅됩니다.

  • JCenter의 지원이 중단되어 mavenCentral을 사용해야한다고 함.

ViewModelScope

ViewModelScope는 앱의 각 ViewModel을 대상으로 정의된 기본 제공 코루틴 Scope 입니다. 이 Scope에서 실행된 모든 코루틴은 ViewModel이 삭제되면 자동으로 취소됩니다.

Android 권한

Android에서 권한의 목적은 Android 사용자의 개인정보를 보호하는 것입니다. Android 앱은 연락처, 통화 기록 같은 민감한 사용자 데이터와 카메라나 인터넷 같은 특정 시스템 기능에 액세스할 수 있는 권한을 선언하거나 요청해야 합니다.

Android에서의 권한

예외(Exception)

예외는 컴파일 시간이 아닌 런타임 시 발생할 수 있는 오류로, 사용자에게 알리지 않고 앱을 갑자기 종료합니다. 이로 인해 사용자 경험이 저하될 수 있습니다. 예외 처리는 앱이 갑자기 종료되지 않도록 하는 메커니즘이며 사요자 친화적인 방법으로 처리됩니다.

kotlin 예외 처리

인터넷 이미지 표시하기

웹 URL에서 사진을 표시하는 것은 간단해 보일 수 있지만 제대로 작동하려면 엔지니어링이 상당히 필요합니다. 이미지를 다운로드하고, 내부적으로 저장하고, 압축 형식에서 Android가 사용할 수 있는 이미지로 디코딩해야 합니다. 이미지는 메모리 내 캐시나 저장소 기반 캐시 또는 두 캐시 모두에 캐시해야 합니다. UI가 응답성을 유지하기 위해 이 모든 작업은 우선순위가 낮은 백그라운드 스레드에서 이루어져야 합니다. 또한 최상의 네트워크 및 CPU성능을 위해 둘 이상의 이미지를 한 번에 가져오고 디코딩하는 것이 좋습니다.

꿀팁

  • 함수 호출에서 괄호 사이에 커서를 놓고 Ctrl+P 를 누르면 함수에서 사용하는 매개변수를 보여주는 도움말이 표시됨.
  • Emulator 에서 메뉴 중 ... (Extension Controls) 에서 Record and Playback 을 이용해서 에뮬레이터의 화면을 녹화해서 gif로 저장할 수 있음.
    • 버그를 공유할 때 등 에 유용
  • 패키지 내에서 필요한 함수가 하나인 경우, import를 사용하는 것보다 직접 패키지명까지 명시해주는 것이 더 간단하고, 패키지 내에서 사용하고자 하는 함수가 여러 개인 경우, import를 사용하는 것이 더 쉽다.
  • 컬러 멋지게 사용하는 방법
  • Android 스튜디오의 Design Editor에서 어두운 테마를 확인하는 방법
  • View를 배치할 때 세로로 정렬하고 요소 사이의 간격을 늘리면 요소들이 복잡하지 않게 배치됩니다.
  • 추상 메서드를 구현해야할 때, 상속받은 클래스 이름에 커서를 놓고 Ctrl + I를 누르면 구현해야하는 메서드 목록이 표시됨.

기타 중요한 문장

  • main() 함수를 호출하는 대신 Android 시스템은 앱이 처음 열릴 때 MainActivityonCreate() 메서드를 호출합니다.
  • Android는 여러 클래스의 프레임워크를 제공하여 Android 앱 작성을 더 쉽게 하지만 어떤 클래스를 의미하는지 정확하게 알아야 합니다.
  • 프로그램에서 피드백을 받지 못하면 사용자는 프로그램이 고장이 난 것이라 생각하게 될 수 있습니다. 사용자가 수행한 작업에 항상 응답을 제공하는 것이 좋습니다.
  • 사용자에게 항상 구체적인 정보를 제공하여 결과를 사용자가 잘 알게 합니다.
  • 타겟은 함께 번들로 제공되는 클래스 모음의 소프트웨어 개발 용어입니다.
  • 개발자는 깔끔하게 보이지 않더라도 부분적으로 작동하는 간단한 버전의 앱을 준비한 후 나중에 완전히 작동하고 시각적으로도 세련된 앱을 만드는 방식으로 작업하는 때가 많습니다.
  • 런처 아이콘 애셋이 drawable 디렉터리에 있는 다른 앱 애셋과는 달리 mipmap 디렉터리에 있는 이유가 궁금할 수 있습니다. 일부 런처가 기기의 기본 밀도 버킷에서 제공한 것보다 큰 크기로 앱 아이콘을 표시할 수 있기 때문입니다. 예를 들어 hdpi 기기에서 특정 기기 런처가 xhdpi 버전의 앱 아이콘을 대신 사용하려고 할 수 있습니다.
  • 흐릿한 앱 아이콘을 방지하려면 각 밀도 버킷(mdpi, hdpi, xhdpi 등)에 다양한 비트맵 이미지의 앱 아이콘을 제공해야 합니다. 기기 화면 밀도는 정확히 160dpi, 240dpi, 320dpi 등이 아닙니다. 현재 화면 밀도를 바탕으로 Android는 가장 가까운 큰 밀도 버킷의 리소스를 선택한 후 축소합니다.
  • Android의 이전 전과의 호환성을 위해 각 밀도 버킷(mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi)에 다양한 버전의 앱 아이콘 비트맵 이미지를 제공합니다.(레거시 런처 아이콘)
  • 함수 본문에서 특정 람다 매개변수를 사용하지 않는 경우 이름은 _ 로 지정하면 코드를 깔끔하게 유지하고 코드 가독성을 높일 수 있습니다.
  • Kotlin과 일반적인 프로그래밍에서는 속성 이름 앞에 밑줄이 있는 것을 자주 볼 수 있습니다. 일반적으로 속성에 직접 액세스하지 못하도록 하기 위함입니다.
profile
Junior Mobile 개발자

0개의 댓글