안드로이드 개발자 가이드에서 봤던 유용한 내용들을 적어놓으려 한다.
(계속 수정될 예정)
쉽게 말하면 코틀린의 이름 규칙을 정리해놓은 문서이다.
출력을 변경하지 않고 더 효율적으로 또는 더 쉽게 작업할 수 있도록 코드를 변경하는 것
{} 안의 내용을 n번 반복하는 루프문
// n번 =를 출력 후 개행하는 함수
fun printBorder(n: Int) {
repeat(n) {
print("=")
}
println()
}
큰 그림부터 시작하여 세부정보를 추가하는 것
어떻게 프로그램을 구성할지 즉, 변수, 함수의 이름과 인수 등을 먼저 main에 작성해놓고, 세부적인 구현은 그 후에 하는 방식
Android 시스템에서 앱을 고유하게 식별하기 위해 사용하는 이름
소프트웨어 관점에서 테스트는 소프트웨어가 올바르게 작동하는지 확인하는 구조화된 방법입니다.
테스트란 정확히 무엇인가요? 테스트는 앱 코드의 일부를 실행하는 Android Studio 프로젝트에 포함된 코드 조각으로, 앱 코드가 예상대로 동작하는지에 따라 테스트에 통과 하거나 실패할 수 있습니다.
test 폴더에 있음.app/build.gradle 파일에 testImplementaton으로 표시된 종속 항목org.junit.test 라이브러리에서 가져온 @Test Annotation을 달아서 컴파일러가 이 Annotation이 표시된 메서드는 테스트임을 알 수 있음.assertEqual() 메서드는 예상 값(expected)이 비즈니스 로직을 통해 가져온 실제 값(actual)과 같아야 한다고 어설션 하는 메서드assertEquals()assertNotEquals()assertThat()assertTrue()assertFalse()assertNull()assertNotNull()app/build.gradle 파일에 androidTestImplementation으로 표시된 종속 항목@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
@After
@BeforeClass
@JvmStatic Annotation과 함께 사용되어야 하며, companion object 내부에 포함되어야 함.@AfterClass
@JvmStatic Annotation과 함께 사용되어야 하며, companion object 내부에 포함되어야 함.APK는 기기나 에뮬레이터에서 앱을 실행하는 데 필요한 파일과 모든 코드를 포함하는 압축 파일입니다.
앱을 작성할 때는 특정 시점에 다른 언어로 번역될 수 있음을 기억해야 합니다.
접근성을 위한 적절한 코딩 사례를 따르면 장애가 있는 사용자를 포함하여 사용자가 모두 더 쉽게 앱을 탐색하고 앱과 상호작용할 수 있습니다.

tools:text 를 통해 참조 가능.
Activity는 앱이 UI를 그리는 창을 제공합니다.
MainActivity라고 함.File > Settings > Editor > General > Auto Import

Add unambiguous imports on the fly
Optimize imports on the fly
팀으로 작업할 때 팀원들은 유사한 방식으로 코드를 작성하여 코드 전체에서 일관성이 유지되도록 하는 것이 좋습니다. 이런 이유로 Android에는 Android 코드 작성 방법에 관한 스타일 가이드(이름 지정 규칙, 서식 지정 및 준수할 기타 우수 사례 등)가 있습니다.
ctrl+A 로 코드를 전체 선택한다.ctrl+Alt+L로 코드를 자동으로 깔끔하게 변경할 수 있다.코드에 주석을 추가하여 작성한 코드에서 발생하는 작업을 설명합니다. 코드가 점점 복잡해짐에 따라 이렇게 작동하도록 코드를 작성한 이유를 기록하는 것도 중요합니다. 변경하려고 나중에 코드로 돌아오면 코드가 하는 작업은 여전히 명확하지만 코드를 이렇게 작성한 이유는 기억나지 않을 수도 있습니다.
작성한 각 클래스 및 각 메서드에 주석을 추가하는 것이 일반적입니다. 주석 시작과 끝 부분에
/**및**/기호를 사용하여 시스템에 코드가 아니라고 알립니다.
메서드 내에서는 코드 리더에 도움이 된다면 자유롭게 주석을 추가할 수 있습니다. 주석 시작 부분에
//기호를 사용할 수 있습니다.
주석과 서식이 모두 변경되면 앱을 다시 실행하여 예상대로 작동하는지 확인하는 것이 좋습니다.
UI 구성요소를 더 추가하고 제약조건을 추가 및 삭제하므로
View가
다른View와 겹쳐 뒤에 있는View를 선택하기 어려울 수 있습니다. 이 경우에는 대신 Component Tree에서View를 선택할 수 있습니다.
View > Tool Windows > Resource Manager
밀도 독립형 픽셀(dp)을 단위로 사용하여 이러한 크기를 정의하면 픽셀 해상도가 다른 기기에서 이미지 크기가 적절하게 조정됩니다.
Annotation은 코드가 컴파일되는 방법을 변경할 수 있는 코드의 메타데이터 태그로 생각하면 됩니다.
Log클래스는 Logcat에 메시지를 씁니다.
Android 앱에서 출력 로깅 권장사항은 Log 클래스를 사용하는 것입니다.
출력 로깅 함수
Log.v() : 자세한 메시지Log.d() : 디버그 메시지Log.i() : 정보 메시지Log.w() : 경고 메시지Log.e() : 오류 메시지매개변수
클래스에서 TAG 상수를 선언하는 것이 좋습니다.
const val TAG = "MainActivity"
그리고 아래와 같이 후속 로그 메서드 호출에서 이를 사용합니다.
Log.d(TAG, "onCreate Called")
Logcat은 메시지를 기록하는 콘솔입니다.
Log.d()메서드나 기타Log클래스 메서드를 사용하여 로그에 명시적으로 전송하는 메시지를 비롯하여 앱에 관한 Android의 메시지가 여기에 표시됩니다.
Logcat에는 많은 메시지가 포함될 수 있지만 대부분은 유용하지 않습니다. Logcat 항목을 다양한 방식으로 필터링할 수 있지만 검색이 가장 쉬운 방법입니다.
로그 메시지에는 날짜 및 시간, 패키지 이름, 로그 태그, 실제 메시지가 포함됩니다.
답변이 유사하지만 정확히 같지는 않은 질문이 많을 수 있으므로 답변을 직접 검색할 때 다음 팁을 염두에 두세요.
- 답변이 얼마나 오래되었나요? 몇 년 전 답변은 더 이상 관련이 없거나 오래된 버전의 언어나 프레임워크를 사용하고 있을 수 있습니다.
- 답변에서 자바나 Kotlin을 사용하나요? 문제가 특정 언어나 특정 프레임워크에만 관련이 있나요?
- accepted(수락됨) 로 표시되거나 찬성 투표가 많은 답변이 더 유용할 수 잇지만 다른 답변도 여전히 중요한 정보를 제공할 수 있다는 점에 유의합니다.
Android에서는 거의 모든 것이 리소스입니다. 따라서 앱에서 액세스할 수 있는 리소스를 정의하는 것이 Android 개발의 필수 요소입니다.
리소스는 색상, 이미지, 레이아웃, 메뉴, 문자열 값을 정의하는 것부터 모든 것에 사용됩니다. 이 경우 이점은 어떤 것도 하드코딩되지 않는다는 점입니다. 모든 것이 이러한 리소스 파일에서 정의되고 애플리케이션의 코드 내에서 참조될 수 있습니다. 이러한 리소스 중 가장 간단하고 가장 일반적인 것은 유연하고 현지화된 텍스트를 허용하는 문자열 리소스를 사용하는 것입니다.
추상 클래스는 완전히 구현되지 않아서 인스턴스화 할 수 없는 클래스입니다. 스케치라고 생각하면 됩니다. 스케치를 통해 무언가에 관한 아이디어와 계획을 통합하지만 그 무언가를 빌드하기에는 일반적으로 정보가 충분하지 않습니다. 스케치(추상 클래스)를 사용하여 청사진(클래스)을 만들고 청사진을 통해 실제 객체 인스턴스를 빌드합니다.
클래스 헤더에
class SquareCabin(residents: Int) ...가 표시됩니다.
실제로는class SquareCabin constructor(residents: Int) ...의 약어입니다.
constructor는 클래스에서 객체 인스턴스를 만들 때 호출됩니다. 예를 들어SquareCabin(4)를 호출하면SquareCabin의constructor가 호출되어 객체 인스턴스를 초기화합니다.
constructor는 전달된 인수를 비롯하여 클래스의 모든 정보에서 인스턴스를 빌드합니다. 클래스가 상위 클래스에서 속성과 함수를 상속받을 때constructor는 상위 클래스의constructor를 호출하여 객체 인스턴스 초기화를 완료합니다.
기본적으로 Kotlin에서 클래스는 final 클래스이며 서브클래스로 분류할 수 없습니다.
abstarct클래스나open키워드로 표시된 클래스에서만 상속할 수 있습니다.
<TextView
android:text="Hello World!"
/>
<TextView
android:text="Hello World!"
></TextView>
이 UI 구성요소는
androidx로 시작하므로 Jetpack의 일부인 것을 알 수 있습니다.
xmlns는XML 네임스페이스를 나타내고 각 줄은 스키마나 이러한 단어와 관련된 속성의 어휘를 정의합니다. 예를 들어android:네임스페이스는 Android 시스템에서 정의한 속성을 표시합니다. 레이아웃 XML의 속성은 모두 이러한 네임스페이스 중 하나로 시작합니다.
리소스 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 속성의 종류
상위 요소의 너비와 같기를 바라므로 너비를
match_parent로 설정해야 한다고 생각할 수 있습니다.ConstraintLayout의 UI 요소에는match_parent를 설정할 수 없습니다. 대신 뷰의 시작 및 끝 가장자리를 제한하고 너비를0dp로 설정해야 합니다. 너비를0dp로 설정하면 시스템에서 너비를 계산하지 않고 뷰에 적용된 제약 조건을 일치시키려고만 합니다.
match_parent는ConstraintLayout의 뷰에는 사용할 수 없습니다. 대신 일치 제약 조건을 의미하는0dp를 사용하세요
Gradle은 Android 스튜디오에서 사용하는 자동화된 빌드 시스템입니다. 개발자가 코드를 변경하거나 리소스를 추가하거나 그 외의 방식으로 앱을 변경할 때마다 Gradle이 변경된 사항을 파악하여 앱을 다시 빌드하는 데 필요한 조치를 취합니다. 또한 에뮬레이터 또는 실제 기기에 앱을 설치하고 실행을 제어합니다.
Android 프레임워크는 여기에 필요한 작업(
View의 ID가 주어지면 이 뷰에 대한 참조를 반환하는 작업)을 정확히 실행하는findViewById()메서드를 제공합니다. 이 접근 방식은 효과적이지만 앱에 뷰를 더 많이 추가하고 UI가 더 복잡해짐에 따라finViewById()를 사용하는 것이 번거로워질 수 있습니다.편의를 위해 Android는 뷰 결합(View Binding)이라는 기능도 제공합니다. 사전에 조금만 더 작업하면 뷰 결합을 통해 UI의 뷰에서 메서드를 훨씬 더 쉽고 빠르게 호출할 수 있습니다. Gradle에서 앱의 뷰 결합을 사용 설정하고 몇 가지 코드를 변경해야 합니다.
결합(Binding) 클래스 이름은 XML 파일의 이름을 파스칼 표기법으로 변환하고 이름 끝에 Binding을 추가한 형태가 됩니다. 마찬가지로 각 뷰를 위한 참조는 밑줄을 삭제하고 뷰 이름을 카멜 표기법으로 변환하여 생성됩니다. 예를 들어 파스칼 표기법의 경우
activity_main.xml은ActivityMainBinding이 되고binding.textView로@id/text_view에 액세스할 수 있습니다.
binding.costOfService.text
binding.costOfService 라는 UI 요소에 대한 참조에 곧바로 .text를 붙여서 해당 요소의 text 속성을 가져오는 것.Kotlin은 다양한 유형의 숫자 형식을 지정하는 메서드를 제공합니다. 그런데 팁 금액은 약간씩 다르며 통화 가치를 나타냅니다. 국가마다 서로 다른 통화를 사용하며 십진수 형식 지정 규칙이 다릅니다. 예를 들어 1234.56의경우 미국 달러로는 $1,234.56 형식으로 표시되지만 유로화로는 €1.234,56 형식으로 표시됩니다. 다행히 Android 프레임워크에서는 숫자를 통화 형식으로 지정하는 메서드를 제공하므로 개발자가 모든 경우의 수를 알 필요가 없습니다. 사용자가 스마트폰에서 선택한 언어 및 기타 설정에 따라 시스템이 자동으로 통화 형식을 지정합니다.
// 숫자를 통화 형식으로 지정하는 데 사용할 수 있는 숫자 형식 지정 클래스
NumberFormat.getCurrencyInstance()
회색 선(경고를 표시하는 밑줄)은 매우 감지하기 어려워 간과하기 쉽습니다. 파일 전체를 검토하여 회색 선을 더 많이 찾을 수도 있지만, 모든 추천을 확인할 수 있는 더 간단한 방법이 있습니다.
머티리얼은 개발자가 Android와 기타 플랫폼에서 고품질 디지털 환경을 구축할 수 있도록 Google이 만든 설계 시스템입니다. 전체 머터리얼 시스템에는 앱에 맞는 시각적 디자인, 모션 디자인, 상호작용 디자인에 관한 가이드라인이 포함되어 있습니다.
머티리얼 디자인은 물체가 빛을 반사하고 그림자를 드리우는 방식을 포함하여 실제 세계와 질감에서 영감을 받았습니다. 읽기 쉽고 매력적이며 일관된 방식으로 앱 UI를 빌드하는 방법에 관한 가이드라인을 제시합니다.
Material Studies - 머티리얼을 이용한 예제를 통한 학습
머티리얼 테마를 사용하면 색상, 서체, 도형을 맞춤설정하는 방법으로 앱에 맞게 머티리얼 디자인을 조정할 수 있습니다. 머터리얼 디자인에는 그대로 사용할 수 있도록 기본으로 제공되는 기준 테마가 있습니다. 이 테마를 원하는 만큼 맞춤설정하여 머터리얼을 앱에 적합하게 할 수 있습니다.
색은 우리 주변, 즉 실제 세계와 디지털 세계 모두에 있습니다. 색에 관해 첫 번째로 알아야 하는 것은 사람마다 색을 보는 방식이 다르다는 것입니다. 따라서 사용자가 앱을 효과적으로 사용할 수 있도록 앱의 색상을 선택하는 것이 중요합니다. 충분히 대비되는 색을 사용하여 색상을 선택하는 것은 더 액세스하기 쉬운 앱을 빌드하는 방법 중 하나입니다.
색상은 색의 빨간색, 녹색, 파란색(RGB) 구성요소를 나타내는 3개의 16진수 숫자(#00~#FF(0~255))로 표현할 수 있습니다. 숫자가 클수록 구성요소의 색이 더 많이 포함됩니다.
또한, 색상은 투명도를 나타내는 알파 값(#00~#FF)을 포함하여 정의할 수 있습니다(#00=0%=완전 투명, #FF=100%=완전 불투명). 알파 값이 포함되는 경우 이 값은 4개의 16진수 숫자(ARGB) 중 첫 번째 숫자입니다. 알파 값이 포함되지 않으면 이 값은 #FF=100%, 즉 불투명으로 간주됩니다.
머티리얼 구성요소는 앱에서 머티리얼 스타일을 더 쉽게 구현할 수 있는 일반적인 UI 위젯입니다.
머티리얼 구성요소를 사용하면 앱이 사용자 기기에 있는 다른 앱과 함께 더 일관된 방식으로 작동합니다. 이렇게 하면 한 앱에서 학습된 UI 패턴이 다음 앱에 이전될 수 있습니다. 따라서 사용자는 앱을 사용하는 방법을 훨씬 더 빠르게 배울 수 있습니다. 가능하면 항상(비 머티리얼 위젯이 아닌) 머티리얼 구성요소를 사용하는 것이 좋습니다. 또한 머티리얼 구성요소는 유연성과 맞춤설정 가능성이 더 높습니다.
아이콘은 의도한 기능을 시각적으로 전달하여 사용자가 인터페이스를 이해하는 데 도움을 주는 기호입니다. 아이콘 디자인은 종종 필요한 최소한의 수준으로 세부 표현을 줄여서 사용자에게 인식되도록 만듭니다.
앱의 아이콘의 경우 다양한 화면 밀도에 맞는 여러 버전의 비트맵 이미지를 제공하는 대신 벡터 드로어블을 사용하는 것이 좋습니다.
머티리언 디자인은 대부분의 요구에 부합하는 다수의 아이콘을 일반적인 카테고리로 정리하여 제공합니다.
이러한 아이콘은 5개 테마(채워짐, 윤곽선 있음, 둥근 모서리, 투톤, 각진 모서리) 중 하나를 사용하여 그릴 수 있으며 색상을 적용할 수 있습니다.
Android Studio의 Asset Studio에서 직접 이 아이콘을 벡터 드로어블로 만들 수 있습니다.
ic_를 사용하는 것이 좋음.스타일을 사용하여 글꼴 색상, 글꼴 크기, 배경 색상과 같은
View의 속성을 지정할 수 있습니다.테마는 개별
View뿐 아니라 앱, 액티비티 또는 뷰 계층 구조 전체에 적용되는 스타일의 모음입니다. 앱, 액티비티, 뷰 또는 뷰 그룹에 테마를 적용하면 요소와 하위 요소 전체에 동일한 테마가 적용됩니다. 또한, 테마를 사용하여 뷰가 아닌 요소(상태 표시줄 및 창 배경)에도 스타일을 적용할 수 있습니다.
테마는 나중에 스타일, 레이아웃 등에 참조할 수 있는 명명된 리소스(테마 속성이라고 함)의 모음입니다. 개별
View뿐만 아니라 전체 앱, Activity, 뷰 계층 구조에도 테마를 지정할 수 있습니다.
앱 템플릿에서는 기본 밝은 테마가 포함되어 있으며 어두운 테마 변형도 포함되어 있습니다. 어두운 테마는 어둡고 더 부드러운 색상을 사용하며 아래와 같은 이점이 있습니다.
- 전력 사용을 크게 줄일 수 있습니다(기기의 화면 기술에 따라 다름).
- 시력이 낮은 사용자와 밝은 빛에 민감한 사용자의 가시성을 개선합니다.
- 조명이 어두운 환경에서 더 편하게 기기를 사용할 수 있습니다.
어두운 테마의 색상 선택하기
어두운 테마의 색상은 읽기 쉬워야 합니다. 어두운 테마는 제한된 강조 색상으로 어두운 표면 색상을 사용합니다. 가독성을 보장하기 위해 기본 색상은 항상 밝은 테마의 기본 색상보다 더 낮은 버전의 채도를 사용합니다.
어두운 테마에서 더 많은 유연성과 사용성을 제공하려면 기본 색상 테마(900~500 사이의 강렬한 톤) 대신 어두운 테마의 밝은 톤(200~50)을 사용하는 것이 좋습니다.
앱에서는 밝은 색상을 기본 색상으로 사용하고 기본 색상을 변형으로 사용하게 됩니다.
어두운 테마에서 앱 바 및 그 외의 넓은 영역은 기본적으로 기본 색상 대신 어두운 배경(colorSurface)으로 표시됩니다. 이는 머티리얼 어두운 테마의 경우 넓은 표시 영역에서 밝은 색상을 더 적게 사용하도록 권장되기 때문입니다. 버튼 또는 그 외의 작은 요소는 정의된 기본 색상을 표시합니다.
색상을 선택하는 가장 쉬운 방법은 머터리얼 팀에서 제공하는 웹 기반 앱인 색상 도구를 사용하는 것입니다. 이 도구는 미리 정의된 색상의 팔레트를 제공하며 이를 통해 다양한 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의 벡터 그래픽 구현으로, 휴대기기에서 충분히 유연하도록 만들어졌습니다. 이러한 가능한 요소를 사용하여 XML로 정의할 수 있습니다. 모든 밀도 버킷에 비트맵 애셋 버전을 제공하는 대신 이미지를 한 번만 정의하면 됩니다. 따라서 앱의 크기가 줄어 유지하기가 쉬워집니다.
gradle에 vectorDrawble 요소를 추가해주어야 함.android {
defaultConfig {
...
vectorDrawables.useSupportLibrary = true
}
...
}
비트맵 이미지와 비교해 벡터 드로어블을 사용하는 데는 단점이 있습니다. 예를 들어 아이콘은 단순한 모양으로 구성되기 때문에 벡터 드로어블로 적합할 수 있지만 사진은 일련의 모양으로 설명하기 어려울 수 있습니다. 이 경우 비트맵 애셋을 사용하는 것이 더 효율적입니다.
앱에 적용할 수 있는 한 가지 시각적 개선 사항은 앱 테마의 기본 색상을 기반으로 드로어블의 색조를 조정하는 것입니다.
?attr/colorPrimary로 설정하면, 밝은 테마와 어두운 테마에 설정된 colorPrimary 속성에 따라 앱 아이콘 등의 벡터 드로어블의 색이 변경되기 때문에 조금 저 일관성 있는 디자인이 될 수 있음.적응형 아이콘에만 사용하는 리소스를 모아두는 디렉토리(새로 생성)
이 폴더 구조를 사용하면 적응형 아이콘 파일을 찾고 관리하기가 더 쉬워집니다.
-anydpi-v26스타일은 단일 위젯 유형의 뷰 속성 값 모음입니다. 예를 들어
TextView스타일은 글꼴 색상, 글꼴 크기, 배경색 등을 지정할 수 있습니다. 이러한 속성을 스타일로 추출하면 레이아웃의 스타일을 여러 뷰에 쉽게 적용하고 단일 위치에 유지할 수 있습니다.
res > values 디렉터리에
style.xml이라는 새 파일을 만듭니다.style.xml에서 스타일을 한 번 정의한 후에는 레이아웃의 모든TextView에 적용할 수 있습니다. 스타일을 처음부터 정의할 수도 있지만 MDC 라이브러리의 기존TextView스타일에서 확장할 수 있습니다.구성요소 스타일을 지정할 때는 일반적으로 사용하는 위젯 유형의 상위 스타일에서 확장해야 합니다. 두 가지 이유로 이와 같이 해야합니다. 첫째, 중요한 모든 기본값을 구성요소에 설정합니다. 둘째, 스타일이 계속해서 상위 스타일의 향후 변경사항을 상속합니다.
스타일 이름을 원하는 대로 지정할 수 있지만 권장되는 규칙이 있습니다. 상위 머티리얼 스타일에서 상속하는 경우 유사한 방식으로
MaterialComponents를 앱 이름(TipTime등)으로 바꿔 스타일 이름을 지정합니다. 그러면 변경사항이 고유한 네임스페이스로 이동되어 향후 머티리얼 구성요소에 새로운 스타일이 도입될 때 충돌이 발생할 가능성이 없어집니다. 예를 들면 다음과 같습니다.스타일 이름
Widget.TipTime.TextView가 상위 스타일Widget.MaterialComponents.TextView에서 상속됩니다.스타일의 이름은 상위 스타일의 이름도 반영해야 합니다.
속성을 스타일에서 지정(예:
android:textSize를18sp로 설정)하고 동일한 속성을 레이아웃 파일에서도 지정(예:android:textSize를14sp로 설정)하는 경우 레이아웃에서 설정한 값(14sp)이 실제로 화면에 표시되는 콘텐츠에 적용됩니다.
자주 사용되는 값의 관리 효율성을 높이려면
dimens.xml파일을 만듭니다.이름을 지정할 수 있는 공통적인 치수를 보유하는
dimens.xml이라는 또 다른 유용한 리소스 파일을res > values에 만들 수 있습니다. 공통적인 값을 명명된 치수로 표준화하면 앱을 더 쉽게 관리할 수 있습니다.
뷰에 키 리스너를 설정하는 코드는 조금 더 복잡합니다. 일반적으로
OnKeyListner에는 키 누름이 발생할 때 트리거되는onKey()메서드가 있습니다.onKey()메서드는 입력 인수 세 개, 즉 뷰, 누른 키의 코드, 키 이벤트를 사용합니다.onKey()메서드가 호출되면handleKeyEvent()메서드를 호출하고 뷰 및 키 코드 인수를 전달해야 합니다.
TalkBack으로 Androd 시작하기
TalkBack 사용 또는 사용 중지하기
음성 안내 지원으로 앱 탐색
Espresso는 Android Studio에서 Android 프로젝트를 만들 때 이러한 프로젝트에 사용할 수 있는 라이브러리로, 이를 사용해 개발자는 코드를 통해 UI 구성요소와 상호작용할 수 있습니다.
Espresso를 사용할 때 어려운 점 중 하나는 라이브러리를 가져오지 않으면 메서드가 자동 완성되지 않는다는 점입니다. 따라서 문서를 조사하지 않으면 Espresso에서 사용 가능한 메서드를 탐색하기 어려울 수 있습니다.
빌더 패턴은 단계별 접근 방식으로 복잡한 객체를 빌드할 수 있는 프로그래밍 디자인 패턴입니다.
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())
}
다음 두 가지 방법으로 패키지를 사용할 수 있습니다.
- 코드의 여러 부분별로 서로 다른 패키지를 만듭니다. 예를 들어, 개발자는 데이터 작업에 사용하는 클래스와 UI를 서로 다른 패키지로 빌드하는 클래스로 구분하는 경우가 많습니다.
- 코드에 있는 다른 패키지의 코드를 사용합니다. 다른 패키지의 클래스를 사용하뎌면 빌드 시스템의 종속 항목에 클래스를 정의해야 합니다. 또한 정규화된 이름(예:
android.widget.TextView) 대신 축약 이름(예:TextView)을 사용할 수 있도록 클래스를 코드에import하는 것도 표준 관행입니다.
앱의 클래스가 많지 않더라도 패키지를 사용하여 기능별로 클래스를 그룹화하는 것이 좋습니다.
패키지 이름은 전역적으로 고유하기만 하다면 어떤 이름이든 사용할 수 있습니다. 위치에 관계없이 게시된 다른 패키지의 이름이 같을 수는 없습니다. 패키지가 너무 많아서 임의의 고유한 이름을 고안하기가 어렵기 때문에 프로그래머는 패키지 이름을 더 쉽게 만들고 이해할 수 있도록 이름 지정 규칙을 사용합니다.
RecyclerView에 표시할 수 있도록 데이터를 가져와 준비하는 역할RecyclerView용 View의 poolapp:layoutManager="LinearLayoutManager"android:scrollbars="vertical"RecyclerView의 각 항목에는 고유한 레이아웃이 있으며, 이 레이아웃은 별도의 레이아웃 파일에서 정의recyclerView.setHasFixedSize(true)RecyclerView의 레이아웃 크기가 변경되지 않는다는 것을 아는 경우에 사용.데이터를 RecylcerView에서 사용할 수 있는 형식으로 조정하는 설계 패턴
RecyclerView.Adapter<ViewHolder>를 상속받아야 함.getItemCount()getItemCount()는 dataset의 크기를 반환해야 함.onCreateViewHolder()ViewHolder가 없는 경우 새 ViewHolder를 만들기 위해 LayoutManager가 호출하는 메서드.parent의 context로 부터 LayoutInflator를 가져와서 inflate한 View에대한 ViewHolder를 반환해주어야 함.onBindViewHolder()LayoutManager가 호출하는 메서드RecyclerView의 단일 항목 뷰를 나타내며 가능한 경우 재사용할 수 있는 객체
RecylcerView에 표시되는 List의 Item에 대한 레이아웃에 있는 개별 View에 대한 참조를 보유함. (이름이 "ViewHolder"인 이유)RecyclerView가 화면에서 뷰를 효율적으로 이동하기 위해 사용하는 정도보 추가단일 하위 뷰를 보유하는데 사용하는 더 간단한 ViewGroup
모든 하위 뷰를 세로 또는 가로의 단일 방향으로 정렬하는 ViewGroup
Android 프레임워크에서 항목 정렬의 처리를 담당
1차원 리스트 형태로 item을 배치
2차원 그리드 형태로 item을 배치.
app:spanCount 속성을 변경해서 열 개수를 조절할 수 있음.클래스 생성자나 메서드의 매개변수 앞에 붙여서 해당 매개변수가 어떤 리소스를 가져와야 하는지를 나타내는 주석. 잘못된 유형의 리소스 ID를 제공하면 경고가 표시됨.
Card View를 사용하면 컨테이너 스타일을 일관되게 유지하면서 간편하게 뷰 그룹을 포함할 수 있습니다.
정렬하기 위해 두 객체를 비교할 때 규칙은 첫 번째 객체가 두 번째 객체보다 작으면 0보다 작은 값을 반환하고 첫 번째 객체가 두 번째 객체보다 크면 0보다 큰 값을 반환하는 것입니다.
// Long Form
calculateButton.setOnClickListener(object: View.OnClickListener {
overrdie fun onClick(view: View?) {
calculateTip()
}
})
// Short Form
calculateButton.setOnClickListener { view -> calculateTip() }
람다에
OnClickListener의onClick()메서드와 동일한 함수 유형이 있는 경우를 관찰합니다(View인수 하나를 사용하고 반환 값이 없음을 나타내는Unit을 반환함).Kotlin의 단일 추상 메서드(SAM) 변환 때문에 축약 버전의 코드가 가능합니다. Kotlin은 람다를 단일 추상 메서드
onClick()을 구현하는OnClickListener객체로 변환합니다. 람다의 함수 유형이 추상 함수 유형과 일치하는 지 확인하면 됩니다.
SAM 변환이란, 인터페이스에 추상 메서드가 하나 뿐일 때, 이 인터페이스의 구현을 그것이 가지고 있는 추상 메서드와 동일한 함수 타입의 함수로 대신하는 것.
참고 : https://beomseok95.tistory.com/92
인텐트는 실행할 작업을 나타내는 객체입니다.
intent 속성)intent 속성은 null 값을 가짐.암시적 인텐트를 사용할 때 Intent의 첫 번째 인자로 전달하는 것. Intent.xxx 형태
ACTION_VIEW : URI를 사용하는 일반적인 인텐트ACTION_SET_ALAM : 백그라운드에서 알람을 설정ACTION_DIAL : 전화를 검CATEGORY_APP_MAPS : 지도 앱을 실행CATEGORY_APP_EMAIL : 이메일 앱을 실행CATEGORY_APP_GALLERY : 갤러리(사진) 앱을 실행putExtra에서 첫 번째 인자로 전달한 이름을 통해 intent를 받은 쪽에서 그 데이터를 검색할 수 있음.companion object로 상수를 선언해서 사용하는 것이 좋다.URL와 URN으로 나누어짐.
https://developer.android.commailto:someone@gmail.comtel:1-555-867-5309앱을 실행하면 상단에 나타나는 바.
앱 이름 표시 뿐만 아니라 바로가기나 더 보기 메뉴 등을 담을 수 있음.
현재 프래그먼트의 기능에 따라 더욱 관련성이 높은 제목을 제공하는 것이 더 나은 사용자 환경입니다.
Activity Lifecycle은 Activity의 전체 기간 중 일련의 Activity 상태입니다. 수명 주기는 Activity가 생성되는 시점에 시작하여 Activity가 소멸되어 시스템에서 Activity 리소스가 회수될 때까지 이어집니다.
Android 개발자는 Activity 수명 주기를 파악해야 합니다. Activity가 수명 주기 상태 변경에 올바르게 응답하지 않으면 앱에 이상한 버그가 발생하여 사용자가 동작을 혼동하거나 앱에서 Android 시스템 리소스를 너무 많이 사용할 수 있습니다. Android 수명 주기를 파악하고 수명 주기 상태 변경에 올바르게 응답하는 것은 좋은 Android 개발자가 되기 위한 중요한 요소입니다.
동작을 변경하거나 Activity 수명 주기 상태가 변경될 때 코드를 실행하려고 할 때가 많습니다. 따라서 Actvity 클래스 자체와 Activity의 모든 서브 클래스(예: AppCompatActivity)는 일련의 수명 주기 콜백 메서드를 구현합니다. Android에서는 Activity가 한 상태에서 다른 상태로 이동할 때 이러한 콜백을 호출하고 개발자는 이러한 메서드를 자체 Activity에서 재저으이하여 수명 주기 상태 변경에 응답해 작업을 실행할 수 있습니다.
onCreate()메서드를 재정의할 때 슈퍼클래스 구현을 호출하여 Activity 생성을 완료해야 하므로 Acitivity 내에서super.onCreate()를 즉시 호출해야 합니다. 다른 수명 주기 콜백 메서드의 경우에도 마찬가지입니다.
Activity는 코드에서 수동으로 Activity의
finish()메서드를 호출하거나 사용자가 앱을 강제 종료하는 경우에도 완전히 종료될 수 있습니다. 예를 들어 사용자는 최근 화면에서 앱을 강제 종료하거나 닫을 수 있습니다. Androd 시스템은 앱이 오랫동안 화면에 표시되지 않으면 자체적으로 Activity를 종료할 수도 있습니다. Android는 배터리를 보존하고 앱의 리소스를 다른 앱에서 사용할 수 있도록 이 작업을 실행합니다.
Activity는 사용자가 Activity에서 벗어날 때마다 완전히 닫히지 않습니다.
- Activity가 화면에 더 이상 표시되지 않으면 이는 Activity가 백그라운드에 배치되는 것입니다. 이와 반대의 경우는 Activity가 포그라운드에 있거나 화면에 표시되는 것입니다.
- 사용자가 앱으로 돌아오면 동일한 Acitivity가 다시 시작되어 화면에 다시 표시됩니다. 수명 주기에서 이 부분을 앱의 표시 수명 주기라고 합니다.
앱이 다시 시작되고
onResume()이 호출되면 앱은 사용자 포커스를 확보합니다. 즉, 사용자가 앱과 상호작용할 수 있습니다. 앱이 완전히 화면에 표시되고 사용자 포커스를 보유하는 수명 주기 부분은 대화형 수명 주기라고 합니다.
onStart()가 호출되면 Activity가 화면에 표시됨.onRestart()는 onStop() 이후 Activity가 다시 화면에 표시될 때(예: 홈 화면으로 갔다가 돌아올 때) 실행됨.onRestart() 실행 후에 onStart()도 함께 실행 됨.onPause() 호출 시 앱에 더 이상 포커스가 없음.onPause()에서 실행되는 모든 코드는 다른 항목이 표시되는 것을 차단하므로 onPause()의 코드는 가볍게 유지하는 것이 좋음.onPause()가 호출되는데, onPause()가 너무 무거우면 수신 전화 알림을 지연시켜 문제가 될 수 있음.onStop() 이후에는 앱이 더 이상 화면에 표시되지 않음.onDestroy()의 실행은 Activity가 완전히 종료되었으며 가비지 컬렉션될 수 있음을 의미함.(호출 이후 시스템이 메모리 정리를 시작함)포커스와 가시성의 차이가 중요한 이유는 Activity가 화면에 부분적으로 표시되지만 사용자 포커스는 없을 수 있기 때문입니다.
onPause()만 사용한 중단은 보통 Activity로 돌아가거나 다른 Activity 또는 앱으로 이동하기 전에 잠시 지속됩니다. 일반적으로 UI를 계속 업데이트하여 나머지 앱이 멈춘 것처럼 보이지 않도록 하는 것이 좋습니다.
구성 변경은 기기 상태가 매우 급격하게 변경되어 시스템이 변경사항을 확인하는 가장 쉬운 방법이 활동을 완전히 종료하고 다시 빌드하는 것일 때 발생합니다.
- 사용자가 기기 언어를 변경하면 다른 텍스트 방향과 문자열 길이를 수용하도록 전체 레이아웃을 변경해야 할 수 있습니다.
- 사용자가 기기를 도크에 연결하거나 물리적 키보드를 추가하면 앱 레이아웃은 다른 디스플레이 크기나 레이아웃을 활용해야 할 수 있습니다.
- 기기 방향이 변경되면(기기가 세로 모드에서 가로 모드 또는 이와 반대로 회전하는 경우) 새 방향에 맞게 레이아웃을 변경해야 할 수 있습니다.
구성 변경이 발생하면 Android는 모든 Activity 수명 주기의 종료 콜백을 호출합니다. 그런 다음 Android는 처음부터 Activity를 다시 시작하여 모든 수명 주기 시작 콜백을 실행합니다.
onStop() 호출 이후에 호출됨.onSaveInstanceState() 재정의는 두 가지가 있음.outState 매개변수만 있는 경우outState 매개변수와 outPersistentState 매개변수가 있는 경우onStart() 호출 이후에 호출됨.onSaveInstanceState() 메서드에서 채워진 Bundle이 onCreate(Bundle)와 onRestoreInstanceState(Bundle) 두 수명 주기 메서드에 모두 전달됨.onCreate()에서 Activity 상태를 복원하지만, onCreate()가 호출된 후 일부 상태를 복원해야 할 때 onRestoreInstanceState(Bundle)을 사용하면 됨.
Bundle은 키-값 쌍 모음으로, 키가 항상 문자열입니다.Int및Boolean값과 같은 간단한 데이터를 번들에 넣을 수 있습니다.
시스템이 이 번들을 메모리에 유지하므로 번들의 데이터를 작게 유지하는 것이 좋습니다. 이 번들의 크기도 제한되지만 기기마다 크기는 다릅니다. 너무 많은 데이터를 저장하면TransactionTooLargeException오류로 인해 앱이 비정상 종료될 수 있습니다.
putInt()메서드와putFloat()및putString()과 같은Bundle클래스의 유사한 메서드는 두 가지 인수를 사용합니다. 키 문자열과 저장할 실제 값입니다.
getInt()메서드는 두 가지 인수를 사용합니다.
- 키 역할을 하는 문자열
- 번들의 키에 값이 없는 경우를 위한 기본 값
onSaveInstanceState()와 onCreate() 또는 onRestoreInstanceState()에서 동일한 키 값을 사용해야 하므로 키는 클래스 외부에 컴파일 타임 상수(const val)로 선언하는 것이 좋음.앱이 백그라운드로 전환되면
onStop()이 호출된 직후 앱 데이터를 번들에 저장할 수 있습니다.EditText의 콘텐츠와 같은 일부 앱 데이터는 자동으로 저장됩니다.
새로운 버전의 안드로이드 기능을 구 버전의 디바이스에서 사용할 수 있도록 하기 위한 Activity의 Base class 정도로 이해하면 될듯.
자세한 내용은 AppCompatActivity 참조.
둘은 같은 코드
class MainActivity : AppCompatActivity(R.layout.activity_main)
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
프래그먼트는 간단하게 마래 앱의 사용자 인터페이스에서 재사용 가능한 부분입니다.
Lifecycle.State 열거형(enum type)으로 표현되는 다섯 가지 상태CREATED 상태임.CREATED 상태로 전환됨.findViewById()를 호출해서 특정 뷰를 속성에 바인딩하는 곳.STARTED 상태로 전환됨.RESUMED 상태로 전환됨.CREATED 상태로 전환됨.DESTROYED 상태로 전환되기 직전에 호출됨.DESTROYED 상태로 전환됨.프래그먼트에 대한 뷰 바인딩 참조는 Nullable 타입이고, 초기값은 null이어야 함.
onCreateView()가 호출될 때까지 레이아웃을 확장할 수 없기 때문.private val binding get() = _binding!!
여기서
get()은 이 속성이 'get-only'임을 나타냅니다. 즉, 값을 가져올 수 있지만 여기서와 같이 할당되고 나면 다른 것에 할당될 수 없습니다.
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를 사용하면NavController의navigate()메서드를 호출하여 표시되는 Fragment로 교체할 수 있습니다.NavController를 사용하면 시스템의 UP 버튼에 응답하여 이전에 표시된 Fragment로 다시 이동하는 것과 같은 일반적인 작업을 처리할 수도 있습니다.
프래그먼트 간에 데이터를 전달할 때 type safe를 지원하는 Gradle 플러그인
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
navController.navigateUp() 함수가 false를 반환할 경우에만 super.onSupportNavigateUp() 함수를 호출함.|| 연산자는 둘 중 하나만 true이면 되므로, 왼쪽이 false일 경우에만 오른쪽의 문장을 평가함. 이를 Short-circuit evalutaion이라고 함.앱 아키텍처는 일련의 디자인 규칙입니다. 아키텍처는 주택의 청사진과 마찬가지로 앱의 구조를 제시합니다. 훌륭한 햅 아키텍처를 사용하면 유연하고 확장 가능하며 향후 유지관리가 가능한 강력한 코드를 만들 수 있습니다.
아키텍처는 앱에서 클래스 간의 책임을 할당하는 가이드라인을 제공합니다. 앱 아키텍처가 잘 디자인되어 있으면 향후 앱을 확장하고 더 많은 기능을 포함할 수 있습니다. 또한 팀 공동작업도 더 간편합니다.
Android 아키텍처의 기본 클래스 또는 구성요소는 UI 컨트롤러(Activity/Fragment),
ViewModel,LiveData,Room입니다. 이러한 구성요소는 수명 주기의 복잡성을 어느 정도 처리하므로 수명 주기 관련 문제를 피하는 데 도움이 됩니다.
Android Architecture Components
앱 아키텍처 가이드
관심사 분리 디자인 원칙은 각각 별개의 책임이 있는 여러 클래스로 앱을 나눠야 한다는 원칙입니다.
또 하나의 중요한 원칙은 모델에서 UI를 만들어야 한다는 것입니다. 가급적 지속적인 모델을 권장합니다. 모델은 앱의 데이터 처리를 담당하는 구성요소로, 앱의
View객체 및 앱 구성요소와 독립되어 있으므로 앱의 수명 주기 및 관련 문제의 영향을 받지 않습니다.
액티비티와 프래그먼트는 UI 컨트롤러입니다. UI 컨트롤러는 화면에 뷰를 그리고 사용자 이벤트나 사용자가 상호작용하는 다른 모든 UI 관련 동작을 캡처하여 UI를 제어합니다. 앱의 데이터 또는 데이터에 관한 모든 의사 결정 로직은 UI 컨트롤러 클래스에 포함되어서는 안 됩니다.
Android 시스템은 특정 사용자 상호작용을 기반으로 또는 메모리 부족과 같은 시스템 조건으로 인해 언제든지 UI 컨트롤러를 제거할 수 있습니다. 이러한 이벤트는 개발자가 직접 제어할 수 없기 때문에, UI 컨트롤러에 앱 데이터나 상태를 저장해서는 안 됩니다. 대신 데이터에 관한 의사 결정 로직을
ViewModel에 추가해야 합니다.
ViewModel은 뷰에 표시되는 앱 데이터의 모델입니다. 모델은 앱의 데이터 처리를 담당하는 구성요소로, 아키텍처 원칙에 따라 모델에서 UI가 도출 되는 앱을 만들 수 있습니다.
ViewModel은 Android 프레임워크에서 액티비티나 프래그먼트가 소멸되고 다시 생성될 때 폐기되지 않는 앱 관련 데이터를 저장합니다.ViewModel객체는 구성이 변경되는 동안 자동으로 유지되어(액티비티 또는 프래그먼트 인스턴스처럼 소멸되지 않음) 보유하고 있는 데이터가 다음 액티비티 또는 프래그먼트 인스턴스에서 즉시 사용될 수 있습니다.
앱에
ViewModel을 구현하려면 아키텍처 구성요소 라이브러리에서 가져온ViewModel클래스를 확장하고 이 클래스 내에 앱 데이터를 저장합니다.
ViewModel 데이터는 public 변수로 노출하지 않는 것이 좋음.public 버전을 노출하는 것이 좋음.ViewModel은 model 패키지로 분리하여 UI 코드와 분리.프레임워크는 액티비티나 프래그먼트의 범위(Scope)가 유지되는 동안
ViewModel을 유지합니다.ViewModel은 소유자가 화면 회전과 같은 구성 변경으로 인해 소멸되는 경우에도 소멸되지 않습니다. 소유자의 새 인스턴스는 기존ViewModel인스턴스에 다시 연결됩니다.
ViewModel은 연결된 프래그먼트가 분리되거나 액티비티가 완료되면 소멸됩니다.ViewModel이 소멸되기 직전에onCleared()콜백이 호출됩니다.
| 프래그먼트/액티비티(UI 컨트롤러)의 책임 | ViewModel의 책임 |
|---|---|
| 액티비티 및 프래그먼트는 뷰와 데이터를 화면에 그리고 사용자 이벤트에 응답합니다. | ViewModel은 UI에 필요한 모든 데이터를 보유하고 처리합니다. 뷰 계층 구조(예: 뷰 결합 객체)에 액세스하거나 액티비티 또는 프래그먼트의 참조를 보유해서는 안됩니다. |
공유
ViewModel을 사용하여 햅의 데이터를 단일ViewModel에 저장합니다. 앱의 여러 프래그먼트는 activity scope을 사용하여 공유ViewModel에 액세스합니다.
대부분의 프로덕션 앱에서 프래그먼트 간에 데이터를 공유하는 것은 일반적인 사용 사례(use case)입니다.
viewModels() 대리자 클래스 대신 activityViewModels()을 사용.viewModels()는 현재 프래그먼트로 범위(scope)가 지정된 ViewModel 인스턴스 제공. 인스턴스가 프래그먼트마다 달라짐.activityViewModels()는 현재 액티비티으로 범위가 지정된 ViewModel 인스턴스를 제공. 동일한 액티비티의 여러 프래그먼트 간에 인스턴스가 동일하게 유지됨.
LiveData클래스는 Android Architecture Compoenent의 일부이기도 하며 Observed한 데이터 홀더 클래스입니다.
LiveData는 수명 주기를 인식하는 Observable인 데이터 홀더 클래스입니다.
LiveData의 특성은 다음과 같습니다.
LiveData는 데이터를 보유(hold)합니다.LiveData는 모든 유형의 데이터에 사용할 수 있는 래퍼입니다.LiveData는 Observable입니다. 즉,LiveData객체에서 보유한 데이터가 변경되면 Observer에 알림이 제공됩니다.LiveData는 수명 주기를 인식합니다.LiveData에 Observer를 연결하면 Observer는LifecycleOwner(일반적으로 액티비티 또는 프래그먼트)와 연결됩니다.LiveData는STARTED또는RESUMED같은 활성 수명 주기 상태인 Observer만 업데이트합니다.
MutableLiveData는 변경 가능한 버전의LiveData입니다. 즉, 내부에 저장된 데이터의 값을 변경할 수 있습니다.
LiveData / MutableLiveData는 Generic 클래스.LiveData / MutableLiveData 객체의 값은 동일하게 유지되고 이 객체에 저장된 데이터만 변경됨.LiveData 객체 내의 데이터에 액세스하려면 value 프로퍼티 사용LiveData의 observe() 함수에 사용하는 Parameter.ViewLifecycleOwner는 현재 View의 수명 주기를 나타냄?LiveData 가 현재 View의 수명 주기를 인식하고, 이 View가 활성 상태(STARTED, RESUMED) 일 때만 Observer에 알릴 수 있음.데이터 결합을 사용하면 Observable인
LiveData값이 변경될 때 바인딩된 레이아웃의 UI 요소에도 알림이 전송되며 레이아웃 내에서 UI를 업데이트할 수 있습니다.
간단히 말해서 데이터 결합은 코드에서 데이터를 뷰 + 뷰 결합에 결합(뷰를 코드에 결합)하는 것입니다.
결합 표현식은 레이아웃 내에서 레이아웃 속성을 참조하는 속성(attribute properties)(예:
android:text)에서 작성됩니다. 레이아웃 속성은<variable>태그를 통해 데이터 결합 레이아웃 파일의 상단에서 선언됩니다. 종속 변수 중 하나라도 변경되면 'DB 라이브러리`가 결합 표현식을 실행하고 이에 따라 뷰를 업데이트 합니다. 이러한 변경 감지는 데이터 결합 라이브러리를 사용할 때 무료로 제공되는 훌륭한 최적화 기능입니다.
@로 시작하고 중괄호 {}로 래핑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객체를 만들고 이 값을 구성 변경 중에도 유지했다가 요청이 있을 때 반환합니다.
지원 속성을 사용하면 정확한 객체가 아닌 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블록이라고도 함)을 제공합니다. 이니셜라이저 블록에는init키워드 뒤에 중괄호{}가 붙습니다. 이 코드 블록은 객체 인스턴스가 처음 생성되어 초기화 될 때 실행됩니다.
대화상자는 사용자에게 결정을 내리거나 추가 정보를 입력하라는 메시지를 표시하는 작은 창(화면)입니다.
- 일반적으로 전체 화면을 가득 채우지 않음.
- 사용자가 조치를 취해야 계속 진행할 수 있음.
이름에서 알 수 있듯이
Context는 애플리케이션이나 액티비티, 프래그먼트의 컨텍스트나 현재 상태를 나타냅니다.
- 액티비티, 프래그먼트, 애플리케이션과 관련된 정보를 포함
- 일반적으로 리소스, 데이터베이스, 기타 시스템 서비스에 액세스하는 데 사용됩니다.
SpannableString은 추가 정보가 연결된 문자열입니다.
오늘날 대부분의 웹 서버는 REST(REpresentational State Transfer의 약자)라는 일반적인 스테이트리스(Stateless) 웹 아키텍처를 사용해 웹 서비스를 실행합니다. 이 아키텍처를 제공하는 웹 서비스를 RESTful 서비스라고 합니다.
Android Gradle을 사용하면 외부 라이브러리를 프로젝트에 추가할 수 있습니다. 라이브러리 종속 항목 외에도 라이브러리가 호스팅 되는 저장소(repository)도 포함해야 합니다. Jetpack 라이브러리의 ViewModel 및 LiveData와 같은 Google 라이브러리는 Google 저장소에 호스팅됩니다. Retrofit과 같은 대부분의 커뮤니티 라이브러리는 JCenter에서 호스팅됩니다.
ViewModelScope는 앱의 각ViewModel을 대상으로 정의된 기본 제공 코루틴 Scope 입니다. 이 Scope에서 실행된 모든 코루틴은ViewModel이 삭제되면 자동으로 취소됩니다.
Android에서 권한의 목적은 Android 사용자의 개인정보를 보호하는 것입니다. Android 앱은 연락처, 통화 기록 같은 민감한 사용자 데이터와 카메라나 인터넷 같은 특정 시스템 기능에 액세스할 수 있는 권한을 선언하거나 요청해야 합니다.
예외는 컴파일 시간이 아닌 런타임 시 발생할 수 있는 오류로, 사용자에게 알리지 않고 앱을 갑자기 종료합니다. 이로 인해 사용자 경험이 저하될 수 있습니다. 예외 처리는 앱이 갑자기 종료되지 않도록 하는 메커니즘이며 사요자 친화적인 방법으로 처리됩니다.
웹 URL에서 사진을 표시하는 것은 간단해 보일 수 있지만 제대로 작동하려면 엔지니어링이 상당히 필요합니다. 이미지를 다운로드하고, 내부적으로 저장하고, 압축 형식에서 Android가 사용할 수 있는 이미지로 디코딩해야 합니다. 이미지는 메모리 내 캐시나 저장소 기반 캐시 또는 두 캐시 모두에 캐시해야 합니다. UI가 응답성을 유지하기 위해 이 모든 작업은 우선순위가 낮은 백그라운드 스레드에서 이루어져야 합니다. 또한 최상의 네트워크 및 CPU성능을 위해 둘 이상의 이미지를 한 번에 가져오고 디코딩하는 것이 좋습니다.
Ctrl+P 를 누르면 함수에서 사용하는 매개변수를 보여주는 도움말이 표시됨.... (Extension Controls) 에서 Record and Playback 을 이용해서 에뮬레이터의 화면을 녹화해서 gif로 저장할 수 있음.import를 사용하는 것보다 직접 패키지명까지 명시해주는 것이 더 간단하고, 패키지 내에서 사용하고자 하는 함수가 여러 개인 경우, import를 사용하는 것이 더 쉽다.
View를 배치할 때 세로로 정렬하고 요소 사이의 간격을 늘리면 요소들이 복잡하지 않게 배치됩니다.main() 함수를 호출하는 대신 Android 시스템은 앱이 처음 열릴 때 MainActivity의 onCreate() 메서드를 호출합니다.drawable 디렉터리에 있는 다른 앱 애셋과는 달리 mipmap 디렉터리에 있는 이유가 궁금할 수 있습니다. 일부 런처가 기기의 기본 밀도 버킷에서 제공한 것보다 큰 크기로 앱 아이콘을 표시할 수 있기 때문입니다. 예를 들어 hdpi 기기에서 특정 기기 런처가 xhdpi 버전의 앱 아이콘을 대신 사용하려고 할 수 있습니다.mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi)에 다양한 버전의 앱 아이콘 비트맵 이미지를 제공합니다.(레거시 런처 아이콘)