24년 말 취업에 성공한 덕분에, 25년은 제게 꽤 풍족한 한 해였습니다.

 

정기적으로 통장에 들어오는 월급 덕분에 예전에는 쉽게 상상하지 못했던 일들을 하나씩 해볼 수 있었어요. 일본 여행도 다녀오고, 큰맘 먹고 비싼 카메라도 구입해 사진을 찍으러 다니기 시작했고, 맥북도 사고, 꾸준히 헬스장도 다니게 되었죠. 돈이라는 큰 제약 없이 하고 싶었던 일들을 시도해 볼 수 있었던 시간이었다고 생각합니다.

 

몸과 마음은 분명 행복했지만, 한편으로는 막연한 불안도 함께 느꼈습니다.
개발자로서 이 일을 얼마나 오래 잘 해낼 수 있을지, 빠르게 변화하는 사회와 AI 시대 속에서 계속 성장하며 지금의 행복을 이어갈 수 있을지 스스로에게 질문하게 되었습니다.

 

그래서 올해는 조금 더 단단해지기로 마음먹었습니다.
기사 자격증 취득을 목표로 공부하고, 다양한 사이드 프로젝트와 자기 계발을 통해 한 걸음이라도 성장하는 한 해를 만들어가려 합니다.

처음에는 취업 전에 사용하던 블로그에 일기처럼 성장 기록을 남기려고 했습니다. 하지만 이미 쌓인 글들 속에서 새로운 기록이 묻혀 버릴 것 같았고, 몇 번 쓰다 그만둘 것 같다는 생각도 들었습니다.

 

그래서 ‘새 술은 새 부대에 담는다’는 마음으로 새로운 블로그를 개설했습니다.

https://study-hard-do-not-give-up.tistory.com/

 

작심3일 필하기

3일에 한번 글쓰는것도 작심 3일에 포함이 되려나

study-hard-do-not-give-up.tistory.com

 

새로운 공간이라면 작은 변화도 더 선명하게 보일 테니까요.

 

오늘은 이렇게 짧은 회고를 남깁니다.
다음에는 또 다른 이야기로 돌아오겠습니다.

본글은 flutter 공부를 위해 아래 영상을 gemini로 요약한것입니다.
https://www.youtube.com/watch?v=3iZAxxa7vdc&list=PL82uaKJraAIJgB8SMOknKQHOnMomaM7Fc&index=1

 


Flutter 위젯, Minecraft로 이해하기

안녕하세요! 이번 포스팅에서는 Flutter 개발의 핵심인 위젯(Widget) 개념을 쉽고 재미있게 설명해 드리려고 합니다. Flutter를 처음 접하는 분들이나 위젯 개념이 아직 어렵게 느껴지는 분들을 위해 Minecraft 게임에 비유하여 자세히 알아보겠습니다.

위젯이란 무엇일까?

Flutter에서 위젯은 화면에 보이는 모든 것을 나타냅니다. 텍스트, 이미지, 버튼 같은 기본적인 요소부터 화면 레이아웃을 구성하는 복잡한 요소까지, 모든 것이 위젯으로 이루어져 있어요. 마치 Minecraft에서 블록 하나하나가 모여 멋진 건축물을 만드는 것과 같습니다.

위젯의 구성 요소: 중첩과 인수

Minecraft에서 집을 짓는 과정을 떠올려볼까요? 집은 기초, 벽, 지붕 등 여러 부분으로 나눌 수 있습니다. Flutter의 위젯도 마찬가지입니다.

  • 중첩(Nesting): 큰 위젯 안에 작은 위젯들이 포함될 수 있습니다. 예를 들어, 집이라는 위젯 안에 기초 위젯, 벽 위젯, 지붕 위젯이 들어갈 수 있죠. 그리고 벽 위젯 안에는 다시 창문 위젯이나 문 위젯이 들어갈 수 있습니다. 마치 Minecraft에서 여러 종류의 블록을 쌓아 올리는 것처럼요.
  • 인수(Arguments): 각 위젯은 인수를 통해 다른 위젯을 내부에 배치할 수 있습니다. 예를 들어, 기초 위젯에는 foundation이라는 인수가 있어서 그 안에 기초 위젯을 넣어줄 수 있습니다. 벽 위젯에는 wall 인수를 통해 벽 위젯을 넣고, 지붕 위젯에는 roof 인수를 통해 지붕 위젯을 넣는 식이죠. 이렇게 인수를 통해 위젯들을 조립하며 복잡한 UI를 구성해 나갑니다.

위젯, 마치 큐브와 모양처럼!

위젯과 인수를 비유하자면, 위젯은 큐브이고 인수는 그 큐브의 특정 모양이라고 생각할 수 있습니다. 우리는 올바른 위젯을 올바른 인수에 할당해야 합니다. 예를 들어, 네모난 구멍에 세모난 블록을 넣을 수 없는 것과 같아요. 정확한 위젯을 올바른 위치에 배치해야 원하는 UI를 만들 수 있습니다.

마치며

Flutter의 위젯은 처음에는 복잡하게 느껴질 수 있지만, Minecraft의 블록처럼 생각하면 훨씬 쉽게 이해할 수 있습니다. 위젯들이 중첩되고 인수를 통해 서로 연결되면서 강력하고 유연한 UI를 만들어낼 수 있다는 점을 기억해주세요.

본글은

https://www.youtube.com/watch?v=HDVyFsFUuVg&list=PLQkwcJG4YTCSVDhww92llY3CAnc_vUhsm&index=7

 

해당 링크의 내용을 Jemini로 요약한 것입니다.


Android Broadcasts 및 Broadcast Receivers: 앱 간 통신 이해하기

Android 앱 개발에서 '브로드캐스트(Broadcast)'는 시스템 전체에 걸쳐 발생하는 이벤트를 앱이 수신하고 반응할 수 있도록 하는 핵심 메커니즘입니다. 이 글에서는 브로드캐스트의 기본 개념, 브로드캐스트 리시버의 종류와 사용법, 그리고 앱 간 통신을 위한 브로드캐스트 전송 방법에 대해 자세히 알아보겠습니다.

브로드캐스트란 무엇인가?

안드로이드에서 브로드캐스트는 시스템 전체에 걸쳐 발생하는 광범위한 이벤트입니다. 이는 안드로이드 운영 체제 자체(예: 기기 부팅 완료, 배터리 부족), 사용자 앱, 또는 다른 앱에서 보낼 수 있습니다. 특정 앱 하나를 대상으로 하는 인텐트(Intent)와 달리, 브로드캐스트는 잠재적으로 많은 앱으로 전송될 수 있습니다. 브로드캐스트를 수신하는 앱은 일반적으로 별도의 화면(액티비티)을 열지 않고 백그라운드에서 조용히 이벤트를 처리하는 경우가 많습니다.

브로드캐스트의 예시로는 다음과 같은 것들이 있습니다.

  • 안드로이드 기기가 완전히 부팅되었을 때 발생하는 '부팅 완료' 이벤트.
  • 전화가 걸려왔을 때 음악 재생 앱이 자동으로 음악을 일시 정지하는 경우.
  • 비행기 모드 전환과 같은 시스템 설정 변경 이벤트.

브로드캐스트 리시버란 무엇인가?

앱이 특정 브로드캐스트에 반응하려면 '브로드캐스트 리시버(Broadcast Receiver)'를 등록해야 합니다. 브로드캐스트 리시버는 특정 브로드캐스트가 발생했을 때 트리거되는 클래스입니다. 이 클래스에는 onReceive 함수가 포함되어 있으며, 브로드캐스트 발생 시 이 함수가 호출되어 원하는 로직을 수행합니다. 브로드캐스트에는 항상 인텐트가 첨부되어 전달되며, 이 인텐트의 액션이나 데이터를 확인하여 어떤 종류의 브로드캐스트인지 파악할 수 있습니다.

브로드캐스트 리시버의 종류: 다이내믹 vs. 스태틱

브로드캐스트 리시버는 등록 방식에 따라 크게 두 가지로 나뉩니다.

1. 다이내믹 브로드캐스트 리시버

다이내믹 브로드캐스트 리시버는 앱이 실행 중인 동안 코드 내에서 동적으로 등록하고 해제하는 방식입니다.

  • 등록: 앱 내부에서 registerReceiver() 함수를 사용하여 등록합니다. 이때 수신할 브로드캐스트의 종류를 정의하는 IntentFilter 객체를 함께 제공합니다.
  • 해제: 더 이상 필요 없을 때 unregisterReceiver() 함수를 사용하여 등록을 해제하는 것이 매우 중요합니다. 일반적으로 액티비티의 onDestroy() 메서드에서 등록을 해제하여 메모리 누수를 방지합니다.
  • 특징: 앱이 활성화되어 있을 때만 작동합니다. 비행기 모드 변경과 같이 앱이 실행 중일 때 실시간으로 반응해야 하는 이벤트 처리에 적합합니다.

2. 스태틱 브로드캐스트 리시버

스태틱 브로드캐스트 리시버는 AndroidManifest.xml 파일에 <receiver> 태그를 사용하여 선언하는 방식입니다.

  • 등록: 매니페스트 파일에 선언되므로 앱이 실행되지 않은 상태에서도 특정 브로드캐스트를 수신할 수 있습니다. 예를 들어, 기기 부팅이 완료되었을 때 앱이 자동으로 특정 작업을 시작하도록 할 수 있습니다.
  • 제한: 배터리 소모 증가 등의 이유로 안드로이드 버전이 올라갈수록 스태틱 리시버의 사용에는 많은 제한이 따릅니다. 현재는 '부팅 완료'와 같이 몇 가지 예외적인 시스템 브로드캐스트에 대해서만 허용되거나, 브로드캐스트가 특정 앱을 명시적으로 대상으로 하는 경우에만 작동합니다.

앱에서 브로드캐스트 보내기

자신의 앱에서 다른 앱이나 앱 내부의 다른 구성 요소로 사용자 정의 브로드캐스트를 보낼 수도 있습니다.

  1. 인텐트 생성: sendBroadcast() 함수를 사용하여 브로드캐스트를 보낼 수 있습니다. 이 함수에는 인텐트를 첨부해야 하며, 인텐트에 사용자 정의 액션 문자열을 지정할 수 있습니다.
  2. 대상 지정 (선택 사항): 특정 앱에만 브로드캐스트를 보내려면 인텐트에 해당 앱의 패키지 이름을 지정할 수 있습니다. 추가 데이터를 전달하고 싶다면 putExtra() 메서드를 사용할 수 있습니다.
  3. 수신: 브로드캐스트를 수신할 앱에서는 해당 사용자 정의 액션을 지정하는 IntentFilter로 브로드캐스트 리시버를 등록해야 합니다.

이러한 방식으로 앱 간의 통신이 가능하지만, 동적 리시버는 수신하는 앱이 열려 있는 경우에만 브로드캐스트를 수신할 수 있다는 점을 유의해야 합니다.

결론

브로드캐스트와 브로드캐스트 리시버는 안드로이드 앱이 시스템 이벤트에 반응하고, 앱 간에 정보를 주고받는 데 필수적인 구성 요소입니다. 다이내믹 리시버는 앱이 활성화된 동안 유용하며, 스태틱 리시버는 앱이 실행되지 않을 때도 특정 중요한 시스템 이벤트를 수신할 수 있지만 그 사용이 제한적입니다. 이들을 올바르게 이해하고 활용한다면 더욱 강력하고 유기적인 안드로이드 앱을 개발할 수 있을 것입니다.

'안드로이드' 카테고리의 다른 글

안드로이드에서 스레드와 코루틴의 차이  (0) 2024.11.06


본글은

https://www.youtube.com/watch?v=2hIY1xuImuQ&list=PLQkwcJG4YTCSVDhww92llY3CAnc_vUhsm&index=6

해당 링크의 내용을 Jemini로 요약한 것입니다.


Android 앱의 소통 방식: 인텐트(Intents)와 인텐트 필터(Intent Filters) 완벽 가이드

Android 앱은 단순히 독립적인 프로그램이 아니라, 서로 유기적으로 소통하고 시스템과 연동하며 작동합니다. 이러한 앱 간 통신 및 구성 요소 실행의 핵심 메커니즘은 바로 인텐트(Intents)와 인텐트 필터(Intent Filters)입니다. 이 글에서는 인텐트의 종류와 사용법, 그리고 인텐트 필터를 통해 앱이 외부 요청에 어떻게 반응하는지에 대해 자세히 알아보겠습니다.


인텐트(Intent)란 무엇인가?

인텐트는 Android 앱의 "의도"를 담아 다른 Android 구성 요소(주로 액티비티, 서비스, 브로드캐스트 리시버)로 전달하는 메시지 객체입니다. 마치 메시지를 담은 "봉투"와 같다고 비유할 수 있습니다. 인텐트는 앱 내부의 구성 요소 간 통신뿐만 아니라, 다른 앱의 구성 요소를 시작하는 데도 사용됩니다.

인텐트의 주요 역할:

  • 다른 액티비티 시작: 앱 내의 다른 화면으로 이동하거나, 다른 앱의 특정 화면을 실행할 때 사용됩니다.
  • 서비스 시작: 백그라운드 작업을 수행하는 서비스를 시작하거나 바인딩할 때 사용됩니다.
  • 브로드캐스트 전송: 시스템 이벤트(예: 배터리 부족, 네트워크 변경)나 앱 내부의 특정 이벤트 발생을 다른 앱이나 구성 요소에 알릴 때 사용됩니다.

인텐트의 두 가지 종류

인텐트는 크게 두 가지 유형으로 나뉩니다.

명시적 인텐트 (Explicit Intents)

특정 대상 구성 요소(액티비티, 서비스 등)를 명확하게 지정하여 실행하는 인텐트입니다. 주로 자체 앱 내부에서 다른 액티비티를 시작할 때 사용됩니다.

예시: Intent(context, SecondActivity::class.java)와 같이 대상 액티비티의 클래스를 직접 명시하여 시작합니다. 다른 앱의 특정 액티비티를 패키지 이름과 클래스 이름을 통해 정확히 지정하여 시작할 수도 있습니다.

암시적 인텐트 (Implicit Intents)

특정 구성 요소를 지정하는 대신, 수행하고자 하는 "액션"만 지정하는 인텐트입니다. Android 시스템은 이 액션을 처리할 수 있는 모든 앱을 찾아 사용자에게 선택기를 표시합니다.

예시:

  • Intent.ACTION_VIEW 액션과 웹 URL을 사용하여 웹 브라우저를 엽니다.
  • Intent.ACTION_SEND 액션과 text/plain 마임 타입을 사용하여 텍스트를 공유할 수 있는 앱 목록을 띄웁니다.
  • Intent.ACTION_DIAL 액션과 전화번호를 사용하여 전화 걸기 화면을 띄웁니다.

인텐트 엑스트라 (Intent Extras)

인텐트에는 putExtra() 메서드를 사용하여 추가적인 데이터를 첨부할 수 있습니다. 이 데이터는 키-값(Key-Value) 쌍의 형태로 전달되며, 문자열, 숫자, Serializable/Parcelable 객체 등 다양한 유형이 가능합니다. 수신하는 액티비티에서는 intent.getStringExtra(), intent.getIntExtra() 등을 사용하여 이 데이터를 검색할 수 있습니다.


인텐트 필터 (Intent Filters): 인텐트 수신 준비

앱의 특정 구성 요소(액티비티, 서비스, 브로드캐스트 리시버)가 암시적 인텐트를 수신할 수 있도록 시스템에 등록하는 메커니즘이 바로 인텐트 필터입니다. 인텐트 필터는 AndroidManifest.xml 파일 내의 <activity>, <service>, <receiver> 태그 안에 <intent-filter> 블록으로 정의됩니다.

인텐트 필터의 주요 구성 요소:

  • <action>: 해당 구성 요소가 처리할 수 있는 인텐트 액션을 지정합니다 (예: android.intent.action.MAIN, android.intent.action.SEND). MAIN 액션과 LAUNCHER 카테고리는 앱의 시작 액티비티를 정의합니다.
  • <category>: 인텐트를 필터링하는 데 사용되는 추가적인 정보를 제공합니다 (예: android.intent.category.DEFAULT).
  • <data>: 해당 구성 요소가 처리할 수 있는 데이터 유형(MIME 타입), URI 스키마, 호스트 등을 지정합니다. 예를 들어, image/*는 모든 이미지 유형을 수신할 수 있도록 합니다.

예시: 이미지를 공유하는 암시적 인텐트를 받아들이는 액티비티를 구현하려면, 해당 액티비티의 인텐트 필터에 android.intent.action.SEND 액션과 image/* 데이터 타입을 명시해야 합니다.


Android 11+의 쿼리 블록 (Queries Block)

Android 10/11부터는 앱의 개인 정보 보호 및 성능 향상을 위해, 앱이 다른 앱의 구성 요소를 암시적으로 쿼리하거나 상호작용하려면 AndroidManifest.xml에 <queries> 블록을 명시적으로 추가하여 어떤 유형의 인텐트를 쿼리할지 선언해야 합니다. 이는 앱이 불필요하게 많은 다른 앱 정보를 얻는 것을 제한하기 위함입니다.


결론

인텐트와 인텐트 필터는 Android 앱 개발에서 필수적인 개념입니다. 이를 통해 앱은 앱 내에서 효율적으로 화면을 전환하고, 다른 앱과 유기적으로 데이터를 주고받으며, 시스템 이벤트에 반응하는 등 복잡한 기능을 구현할 수 있습니다. 명시적 인텐트와 암시적 인텐트의 차이를 이해하고, 인텐트 필터를 올바르게 설정하는 것은 견고하고 유연한 Android 앱을 구축하는 데 매우 중요합니다.


본글은

https://www.youtube.com/watch?v=vj1ZdUfPlJM&list=PLQkwcJG4YTCSVDhww92llY3CAnc_vUhsm&index=5

 

해당 링크의 내용을 Jemini로 요약한 것입니다.


 

Android 리소스와 한정자: 강력한 앱 현지화 및 반응형 UI 구현

Android 앱을 개발할 때 코드로 모든 것을 처리하는 것이 아니라, 앱에 필요한 이미지, 텍스트, 색상, 레이아웃 등 다양한 요소들을 리소스(Resources)로 분리하여 관리합니다. 이는 코드의 가독성을 높이고, 재사용성을 향상시키며, 무엇보다 다양한 장치 구성(Configuration)에 따라 앱이 유연하게 반응하도록 하는 데 필수적입니다.

이 글에서는 Android 리소스의 종류와 사용법, 그리고 특정 장치 환경에 맞춰 리소스를 자동 선택하게 해주는 한정자(Qualifiers)의 개념에 대해 자세히 살펴보겠습니다.

Android 리소스란?

Android 리소스는 앱의 코어 로직(Java/Kotlin)과 분리되어 res (resource) 폴더 아래에 저장되는 모든 비코드 요소입니다. 주요 리소스 폴더는 다음과 같습니다.

  • drawable: PNG, JPEG와 같은 비트맵 이미지뿐만 아니라 SVG 기반의 벡터 그래픽을 저장합니다. 벡터 그래픽은 XML 형태로 변환되어 해상도에 관계없이 선명하게 표시될 수 있다는 장점이 있습니다.
  • mipmap: 주로 앱의 런처 아이콘을 저장하는 데 사용됩니다. 다양한 화면 밀도에 맞는 여러 크기의 아이콘을 제공하여 모든 장치에서 앱 아이콘이 선명하게 보이도록 합니다.
  • values:
    • colors.xml: 앱에서 사용되는 색상 값들을 정의합니다. 라이트 테마/다크 테마 등 테마에 따라 다른 색상 값을 지정할 수 있습니다.
    • strings.xml: 앱에 표시되는 모든 텍스트(버튼 텍스트, 설명, 메시지 등)를 저장합니다. 이는 지역화(Localization)를 통해 앱을 여러 언어로 제공하는 데 핵심적인 역할을 합니다.
    • themes.xml: 앱의 전반적인 스타일과 테마(색상 팔레트, 글꼴, 글꼴 크기 등)를 정의합니다.
  • xml: 다른 리소스 폴더에 속하지 않는 일반적인 XML 기반 구성 파일(예: 특정 위젯 설정, 네트워크 보안 설정)을 저장합니다.
  • layout: (언급되지 않았지만 중요한) 사용자 인터페이스 레이아웃을 정의하는 XML 파일이 저장됩니다.

코드에서는 R.drawable.image_name, R.string.app_name과 같이 R 클래스와 리소스 유형, 리소스 이름을 사용하여 각 리소스의 고유 ID를 참조할 수 있습니다. 액티비티나 프래그먼트와 같이 Context에 접근할 수 있는 환경에서는 resources.getDrawable(), resources.getString() 등의 메서드를 통해 실제 리소스 객체를 가져와 사용할 수 있습니다.

한정자(Qualifiers): 장치 구성에 따른 리소스 제공

한정자는 특정 장치 구성(예: 화면 크기, 언어, API 레벨, 테마 등)에 따라 Android 시스템이 자동으로 적절한 리소스를 선택하도록 해주는 강력한 도구입니다. 개발자는 동일한 리소스 이름에 다른 한정자를 붙인 폴더를 생성하여 특정 조건에 맞는 리소스를 제공할 수 있습니다.

주요 한정자 예시:

  • API 레벨 (v<API_LEVEL>): drawable-v24 폴더는 API 레벨 24(Android 7.0 누가) 이상에서만 사용될 리소스를 포함합니다. 특정 Android 버전에만 제공하고 싶은 기능이나 이미지에 유용합니다.
  • 언어 및 지역 코드 (ko, en-rUS): values-ko/strings.xml은 한국어 사용자를 위한 문자열을, values-en-rUS/strings.xml은 미국 영어 사용자를 위한 문자열을 정의합니다.
  • 화면 너비 (sw<DP>dp): layout-sw600dp 폴더는 화면의 가장 작은 너비가 600dp 이상인 장치(예: 태블릿)에만 사용될 레이아웃 파일을 포함합니다. 이를 통해 태블릿에 최적화된 UI를 제공할 수 있습니다.
  • 야간 모드 (night): drawable-night 폴더는 다크 테마(야간 모드)가 활성화되었을 때 사용될 이미지를 포함합니다. values-night/colors.xml처럼 사용하여 테마에 따라 색상을 변경할 수도 있습니다. 앱이 자동으로 라이트/다크 모드에 맞춰 이미지를 전환하도록 할 수 있습니다.

여러 한정자를 조합하여 더욱 세밀한 구성을 정의할 수도 있습니다. 예를 들어, drawable-night-v29 폴더는 API 레벨 29 이상인 장치에서 야간 모드일 때 사용될 드로어블을 포함합니다. Android Studio는 이러한 한정자를 기반으로 리소스 폴더를 생성하고 정리하여 개발을 돕습니다.

결론

Android 리소스와 한정자를 이해하고 올바르게 활용하는 것은 현대적인 Android 앱을 개발하는 데 매우 중요합니다. 이를 통해 앱은 다음과 같은 이점을 얻을 수 있습니다.

  • 탁월한 사용자 경험: 다양한 장치(스마트폰, 태블릿, 폴더블폰 등)와 설정(언어, 테마)에 최적화된 UI를 제공합니다.
  • 향상된 유지보수성: 코드와 리소스가 분리되어 있어 변경 및 관리가 용이합니다.
  • 효율적인 개발: 재사용 가능한 리소스를 통해 개발 시간을 단축하고 일관된 디자인을 유지할 수 있습니다.

 

본글은

https://www.youtube.com/watch?v=YdnM2ZvrIFM&list=PLQkwcJG4YTCSVDhww92llY3CAnc_vUhsm&index=4

 

해당 링크의 내용을 Jemini로 요약한 것입니다.


Android 개발의 핵심: 컨텍스트(Context)를 완벽하게 이해하기

Android 앱을 개발하면서 Context라는 단어를 수없이 보게 됩니다. 하지만 이 Context가 정확히 무엇이고, 언제 어떤 Context를 사용해야 하는지 명확히 이해하지 못하는 경우가 많습니다. Context는 Android 앱이 운영 체제와 상호작용하고 리소스에 접근하며 다른 구성 요소를 실행하는 데 필수적인 다리 역할을 합니다.

이 글에서는 Android Context의 개념부터 다양한 사용 사례, 그리고 발생할 수 있는 메모리 누수 문제 및 해결 방안까지 심도 있게 다뤄보겠습니다.

컨텍스트(Context)란 무엇인가?

Context는 Android 애플리케이션 환경에 대한 정보를 제공하는 추상 클래스입니다. 쉽게 말해, 앱이 현재 어떤 상태에 있고, 어떤 환경에서 실행되고 있는지에 대한 정보를 담고 있는 객체라고 할 수 있습니다. 앱이 시스템 서비스에 접근하거나, 리소스를 가져오거나, 다른 앱 구성 요소와 통신할 때 Context 객체가 필요합니다.

Context의 일반적인 사용 사례:

  • 리소스 접근: 이미지, 문자열, 색상 등 앱의 res 폴더에 있는 정적 리소스에 접근할 때 Context.getResources().getString(R.string.app_name)처럼 사용됩니다.
  • 파일 시스템 접근 및 데이터 저장: 앱 전용 데이터베이스나 환경설정(SharedPreferences)을 사용하여 Android 장치의 파일 시스템에 데이터를 읽고 쓸 때 Context가 필요합니다.
  • 다른 컴포넌트 실행: 앱 내에서 다른 액티비티를 시작하거나, 서비스를 시작하거나, 브로드캐스트를 전송할 때 Context를 통해 startActivity(), startService(), sendBroadcast()와 같은 메서드를 호출합니다.

결론적으로, Context는 Android 앱과 운영 체제 또는 다른 앱 구성 요소 사이의 중개자 역할을 수행하며, Android 생태계에 연결되기 위한 필수적인 객체입니다.

컨텍스트의 종류: 액티비티 컨텍스트 vs. 애플리케이션 컨텍스트

Context는 Activity, Service, Application 등 Android의 주요 구성 요소 클래스의 슈퍼클래스입니다. 이는 이들 클래스 자체가 Context의 기능을 가지고 있다는 의미입니다. 주로 사용되는 Context의 두 가지 주요 유형은 다음과 같습니다.

  • 액티비티 컨텍스트 (Activity Context):
    • 특정 액티비티의 생명주기와 연결되어 있습니다.
    • 액티비티가 활성화되어 있는 동안에만 유효하며, 액티비티가 소멸되면 함께 소멸됩니다 (예: 화면 회전 시 액티비티 재생성).
    • 액티비티의 UI와 관련된 작업(예: 다이얼로그 표시, 특정 뷰 접근, 권한 요청)에 사용됩니다.
  • 애플리케이션 컨텍스트 (Application Context):
    • 앱 전체의 애플리케이션 생명주기와 연결되어 있습니다.
    • 앱이 실행되는 동안 계속 유효하며, 앱이 종료될 때만 소멸됩니다.
    • 액티비티 컨텍스트보다 훨씬 긴 수명을 가집니다.
    • UI와 직접적으로 관련 없는 작업이나 액티비티의 생명주기와 독립적인 작업(예: 데이터베이스 초기화, 공유 리소스 접근)에 사용됩니다.

컨텍스트와 메모리 누수(Memory Leak)

Context를 잘못 사용하면 메모리 누수로 이어질 수 있습니다. 특히 액티비티 컨텍스트의 경우, 액티비티보다 수명이 긴 객체(예: 싱글턴, 장기 실행 백그라운드 작업, 뷰 모델)가 액티비티 컨텍스트를 강하게 참조하고 있으면 문제가 발생합니다.

예를 들어, 뷰 모델(ViewModel)은 구성 변경 시에도 소멸되지 않고 유지됩니다. 만약 뷰 모델이 액티비티 컨텍스트를 직접 참조하고 있다면, 액티비티가 소멸된 후에도 뷰 모델이 계속 해당 소멸된 액티비티의 리소스에 대한 참조를 유지하게 됩니다. 이로 인해 가비지 컬렉터가 소멸된 액티비티의 메모리를 회수할 수 없게 되어 메모리 누수가 발생합니다.

메모리 누수를 방지하는 방법:

  • 활동(Activity) 외부에서 액티비티 컨텍스트를 저장하지 마세요.
  • 수명이 긴 객체나 전역적인 싱글턴에서는 애플리케이션 컨텍스트를 사용하세요. 애플리케이션 컨텍스트는 앱의 전체 생명주기와 같으므로 메모리 누수를 유발할 가능성이 훨씬 적습니다.

언제 액티비티 컨텍스트를 사용해야 하는가?

애플리케이션 컨텍스트가 더 안전하지만, 모든 경우에 애플리케이션 컨텍스트를 사용할 수는 없습니다. 특정 상황에서는 액티비티 컨텍스트가 필수적입니다.

  • UI 관련 작업: UI 구성 요소(예: Dialog, Toast 등)를 생성하거나, 특정 뷰에 접근하여 변경하는 등 UI에 직접적으로 영향을 미치는 작업에는 현재 UI를 표현하는 액티비티 컨텍스트가 필요합니다.
  • 권한 요청: 사용자에게 특정 권한(예: 카메라, 마이크)을 요청할 때 ActivityCompat.requestPermissions()와 같은 메서드는 시스템 대화 상자를 앱의 UI 위에 표시해야 하므로 현재 활성화된 액티비티 컨텍스트를 필요로 합니다. 애플리케이션 컨텍스트는 UI와 직접적으로 연결되어 있지 않기 때문에 이러한 작업을 수행할 수 없습니다.

결론

Android Context는 앱의 다양한 기능 구현에 핵심적인 역할을 하지만, 그 복잡성 때문에 오용될 가능성도 높습니다. Activity Context와 Application Context의 차이점, 그리고 각각의 생명주기를 정확히 이해하고 올바른 상황에 적절한 Context를 사용하는 것은 메모리 누수를 방지하고 안정적인 Android 앱을 개발하는 데 매우 중요합니다.

본글은

https://www.youtube.com/watch?v=9sqvBydNJSg&list=PLQkwcJG4YTCSVDhww92llY3CAnc_vUhsm&index=3

해당 링크의 내용을 Jemini로 요약한 것입니다.


Android 앱 개발 핵심: ViewModel과 구성 변경 처리

Android 앱을 개발하다 보면 화면 회전이나 언어 변경과 같은 구성 변경(Configuration Change) 시 기존 화면(액티비티 또는 프래그먼트)이 소멸되고 재생성되는 문제를 자주 마주하게 됩니다. 이 과정에서 화면의 데이터나 상태가 초기화되어 사용자 경험을 저해할 수 있습니다. 이러한 문제를 우아하게 해결하고, UI와 데이터 로직을 분리하여 더욱 견고한 앱을 구축하기 위한 핵심 도구가 바로 뷰 모델(ViewModel)입니다.

뷰 모델(ViewModel)이란 무엇인가?

뷰 모델은 MVVM(Model-View-ViewModel)과 같은 애플리케이션 아키텍처 패턴에서 사용되는 중요한 구성 요소입니다. 뷰 모델은 다음과 같은 역할을 수행합니다.

  • UI와 데이터(모델)의 중간 다리 역할: 뷰(UI, 즉 액티비티나 프래그먼트)는 뷰 모델을 통해 데이터를 관찰하고 업데이트를 받습니다. 뷰 모델은 직접 데이터를 처리하지 않고, 데이터 계층(모델)에서 원시 데이터를 가져와 UI에 표시하기 쉬운 형식으로 변환하여 제공합니다. 예를 들어, Unix 타임스탬프를 사람이 읽을 수 있는 날짜 형식으로 변환하는 역할을 합니다.
  • 사용자 액션 처리: UI에서 발생하는 버튼 클릭과 같은 사용자 액션을 받아 처리하고, 필요한 경우 데이터 계층과 상호작용하여 데이터를 업데이트하거나 새로운 데이터를 가져옵니다.
  • UI 상태 관리 및 알림: 뷰 모델은 UI의 상태를 유지하고 관리하며, 데이터나 상태가 변경될 때 UI에 이를 알림으로써 UI가 최신 상태를 반영하도록 합니다.
  • 화면 당 하나의 뷰 모델: 일반적으로 화면(액티비티 또는 프래그먼트) 당 하나의 뷰 모델을 사용하여 해당 화면의 UI 관련 데이터를 관리하는 것이 권장됩니다.

Android에서 뷰 모델이 특별히 중요한 이유: 구성 변경으로부터 데이터 보호

앞서 언급했듯이 Android는 화면 회전, 키보드 가용성 변경, 다국어 설정 변경 등 구성 변경이 발생하면 해당 액티비티(또는 프래그먼트)를 소멸시키고 다시 생성합니다. 이 과정에서 액티비티 내부에 있던 모든 변수와 상태가 초기화되면서 사용자 입력이나 로딩 중인 데이터가 사라질 수 있습니다.

하지만 androidx.lifecycle.ViewModel을 상속받아 생성된 뷰 모델은 액티비티나 프래그먼트의 생명주기와는 독립적으로 존재하며, 구성 변경 시에도 소멸되지 않고 유지됩니다. 즉, 화면이 재생성되더라도 뷰 모델은 기존 인스턴스를 유지하고 있어 이전에 가지고 있던 데이터를 그대로 보존할 수 있습니다. 이는 사용자에게 끊김 없는 경험을 제공하는 데 필수적입니다.

Android 뷰 모델 사용 방법

Android에서 뷰 모델을 사용하는 것은 매우 간단합니다.

  1. 뷰 모델 클래스 생성: androidx.lifecycle.ViewModel을 상속받는 클래스를 만듭니다.
    class MyViewModel : ViewModel() {
        // UI 관련 데이터와 로직 구현
        private val _myText = MutableLiveData<String>()
        val myText: LiveData<String> = _myText
    
        init {
            _myText.value = "Hello ViewModel!"
        }
    
        fun updateText(newText: String) {
            _myText.value = newText
        }
    }
    
  2. 액티비티/컴포저블에서 뷰 모델 초기화:
    • Activity/Fragment (Kotlin): by viewModels() 델리게이트를 사용하여 뷰 모델 인스턴스를 쉽게 얻을 수 있습니다.
      class MyActivity : AppCompatActivity() {
          private val viewModel: MyViewModel by viewModels()
      
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              // ViewModel의 데이터 관찰 및 UI 업데이트
              viewModel.myText.observe(this) { text ->
                  // TextView.text = text
              }
          }
      }
      
    • Jetpack Compose: viewModel() Composable 함수를 사용하여 뷰 모델 인스턴스를 얻을 수 있습니다. (의존성: androidx.lifecycle:lifecycle-viewmodel-compose)
      @Composable
      fun MyScreen(viewModel: MyViewModel = viewModel()) {
          val text by viewModel.myText.observeAsState()
          Text(text = text ?: "Loading...")
          Button(onClick = { viewModel.updateText("Updated Text!") }) {
              Text("Update")
          }
      }
      

뷰 모델 팩토리(ViewModel Factory) 활용

만약 뷰 모델이 생성자 파라미터(예: 데이터 레포지토리 인스턴스)를 필요로 한다면, Android 시스템은 뷰 모델을 어떻게 생성해야 하는지 알 수 없습니다. 이 경우 ViewModelProvider.Factory 인터페이스를 구현하는 뷰 모델 팩토리를 직접 만들어 뷰 모델 인스턴스 생성 방법을 시스템에 알려줘야 합니다.

class MyViewModelFactory(private val repository: MyRepository) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(MyViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return MyViewModel(repository) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

그리고 액티비티/프래그먼트에서 팩토리를 제공하여 뷰 모델을 초기화합니다.

// Activity
val factory = MyViewModelFactory(MyRepository())
val viewModel = ViewModelProvider(this, factory).get(MyViewModel::class.java)

결론

Android 앱 개발에서 뷰 모델은 구성 변경 시 데이터 손실을 방지하고, UI와 데이터 로직을 명확하게 분리하여 앱의 유지보수성과 테스트 용이성을 크게 향상시키는 강력한 도구입니다. 뷰 모델의 개념과 활용법을 숙지하는 것은 현대적인 Android 앱을 구축하는 데 필수적인 역량입니다.

본글은

https://www.youtube.com/watch?v=Z0AzoFOiH9c&list=PLQkwcJG4YTCSVDhww92llY3CAnc_vUhsm&index=2

 

해당 링크의 내용을 Jemini로 요약한 것입니다.


 
Android 앱의 깊이 있는 이해: 태스크, 백 스택, 그리고 런치 모드

Android 앱을 개발하고 사용하는 과정에서 우리는 수많은 화면 전환과 앱 간의 이동을 경험합니다. 이러한 복잡한 탐색 흐름을 효율적으로 관리하고 사용자에게 끊김 없는 경험을 제공하는 데 핵심적인 역할을 하는 것이 바로 태스크(Task), 백 스택(Back Stack), 그리고 런치 모드(Launch Mode)입니다. 이 글에서는 이 세 가지 개념을 통해 Android 앱의 화면 탐색 원리를 깊이 이해해보고자 합니다.

백 스택(Back Stack): 화면 탐색의 이력서

Android 앱에서 사용자가 화면을 이동할 때마다, 현재 보이는 액티비티(Activity)의 이력이 차곡차곡 쌓이는데, 이것이 바로 백 스택입니다. 백 스택은 말 그대로 "스택(Stack)" 자료 구조처럼 동작합니다.

  • 푸시(Push): 새로운 액티비티로 이동하면 해당 액티비티는 백 스택의 맨 위에 추가(푸시)됩니다.
  • 팝(Pop): 사용자가 뒤로 가기 버튼을 누르면 현재 액티비티는 백 스택에서 제거(팝)되고, 바로 아래에 있던 액티비티가 다시 활성화됩니다.

이러한 메커니즘 덕분에 사용자는 앱 내에서 자신이 거쳐온 경로를 쉽게 되돌아갈 수 있습니다.

태스크(Task): 앱의 백 스택 집합

태스크는 하나 또는 여러 액티비티로 구성된 집합이며, 이 액티비티들이 하나의 백 스택을 형성합니다. 안드로이드 시스템은 동시에 여러 앱의 태스크를 관리할 수 있습니다. 예를 들어, 웹 브라우저를 사용하다가 소셜 미디어 앱의 링크를 클릭하면, 소셜 미디어 앱의 새로운 태스크가 시작되어 별도의 백 스택을 가지게 됩니다.

사용자는 뒤로 가기 버튼을 통해 현재 태스크의 액티비티들을 탐색하다가, 태스크의 가장 아래 액티비티까지 도달하면 이전 태스크(이전에 사용하던 앱)로 돌아갈 수 있습니다. 이는 사용자가 여러 앱을 오가며 작업할 때 각 앱의 상태를 독립적으로 유지하고 자연스럽게 전환할 수 있도록 돕습니다.

런치 모드(Launch Mode): 액티비티 실행 방식의 정의

새로운 액티비티를 시작할 때, 해당 액티비티가 백 스택에 어떻게 추가되고 관리될지를 결정하는 것이 바로 런치 모드입니다. AndroidManifest.xml 파일에서 각 액티비티에 대한 android:launchMode 속성을 설정하여 정의할 수 있습니다. 런치 모드는 다음과 같이 네 가지 주요 유형으로 나뉩니다.

  1. Standard (기본값)
    • 가장 일반적인 런치 모드입니다.
    • 새로운 액티비티를 실행할 때마다 항상 해당 액티비티의 새로운 인스턴스가 생성되어 백 스택의 맨 위에 푸시됩니다.
    • 동일한 액티비티가 백 스택에 여러 번 존재할 수 있습니다.
  2. Single Top
    • 실행하려는 액티비티가 현재 백 스택의 최상단에 이미 존재한다면, 새로운 인스턴스를 생성하는 대신 기존 인스턴스가 재활용됩니다.
    • 중복되는 액티비티 인스턴스 생성을 방지하여 리소스 낭비를 줄일 수 있습니다. 예를 들어, 알림을 클릭했을 때 이미 열려 있는 채팅방으로 이동하는 경우에 유용합니다.
  3. Single Task
    • 이 런치 모드로 설정된 액티비티는 항상 새로운 태스크 내에서 실행됩니다.
    • 만약 해당 액티비티를 포함하는 태스크가 이미 존재한다면, 시스템은 새로운 태스크를 만드는 대신 기존 태스크를 포그라운드로 가져오고, 그 태스크 내의 백 스택 최상단에 있는 액티비티를 활성화합니다. 이때, 호출된 액티비티 위에 있던 모든 액티비티는 스택에서 제거됩니다.
    • 앱의 진입점 액티비티나, 다른 앱에서 특정 콘텐츠를 열기 위한 액티비티(예: 딥 링크 처리)에 주로 사용됩니다.
  4. Single Instance
    • singleTask와 유사하게 새로운 태스크를 생성하지만, 이 태스크에는 오직 해당 액티비티의 인스턴스만 존재할 수 있습니다.
    • 다른 액티비티는 이 singleInstance 태스크 내에서 실행될 수 없습니다. 다른 액티비티가 이 액티비티를 호출하면, 그 액티비티는 별도의 태스크나 호출한 태스크 내에서 실행됩니다.
    • 결제 앱과 같이 다른 앱의 흐름에 영향을 주지 않고 완전히 독립적으로 실행되어야 하는 특정 유형의 액티비티에 적합합니다.

결론

Android 앱의 태스크, 백 스택, 그리고 런치 모드는 복잡해 보이지만, 이 개념들을 이해하고 적절히 활용하는 것은 사용자에게 직관적이고 안정적인 탐색 경험을 제공하는 데 필수적입니다. 앱의 아키텍처를 설계할 때 이러한 원리들을 고려한다면, 더욱 견고하고 사용자 친화적인 앱을 만들 수 있을 것입니다.


과거에 안드로이드 TV에서 결제 모듈을 개발했던 경험이 있습니다. 당시 Van 사의 카드리더기를 안드로이드 셋톱박스에 연결하고, TV 리모컨만으로 조작이 가능하도록 미들웨어를 개발해야 했습니다. 미들웨어에서는 딥링크를 통해 오버레이 형태의 화면을 띄우고, 리모컨 입력을 처리해야 했기에 액티비티의 배경을 투명하게 만들고, SingleInstance 런치 모드로 설정하여 완전히 독립적인 흐름을 구성했습니다.

하지만 당시에는 태스크와 백 스택, 런치 모드에 대한 개념이 부족해 시행착오를 많이 겪었습니다. 이 영상을 미리 보았더라면 구조를 훨씬 더 명확하게 설계할 수 있었을 것이고, 같은 고민을 하고 있는 다른 개발자들에게도 추천합니다.

 

본글은

https://www.youtube.com/watch?v=SJw3Nu_h8kk&list=PLQkwcJG4YTCSVDhww92llY3CAnc_vUhsm  

해당 링크의 내용을 Jemini로 요약한 것입니다.


Android 네이티브 개발 핵심: 액티비티(Activity)와 생명주기 완벽 이해

Android 앱 개발의 가장 기본적인 단위 중 하나는 바로 액티비티(Activity)입니다. 액티비티는 사용자 인터페이스를 갖는 단일 화면을 나타내며, 사용자와 앱 간의 상호작용 단위를 구성합니다. 마치 웹 애플리케이션의 페이지와 유사하다고 생각할 수 있습니다.

본 블로그에서는 Android 네이티브 개발의 핵심인 이 액티비티의 개념과 더불어, 앱의 안정성과 사용자 경험에 직결되는 액티비티 생명주기(Activity Lifecycle)에 대해 심도 있게 다뤄보겠습니다.

액티비티(Activity)란 무엇인가?

액티비티는 앱 내에서 사용자와 상호작용하는 시각적인 요소의 컨테이너 역할을 합니다. 예를 들어, 이메일 앱의 받은 편지함 화면, 지도 앱의 지도 화면, 카메라 앱의 촬영 화면 등이 모두 하나의 액티비티로 구현될 수 있습니다. 앱은 여러 개의 액티비티로 구성될 수 있으며, 사용자는 이러한 액티비티들을 탐색하며 앱의 기능을 이용하게 됩니다.

액티비티는 앱의 진입점 역할을 수행하기도 합니다. 사용자가 앱 아이콘을 탭하면, 앱의 메인 액티비티가 시작되어 사용자에게 첫 화면을 보여주게 됩니다.

액티비티 생명주기(Activity Lifecycle)의 중요성

액티비티는 생성되어 화면에 보여지고, 사용자와 상호작용한 후, 메모리에서 해제되는 일련의 단계를 거칩니다. 이 과정을 액티비티 생명주기라고 합니다. 개발자는 각 생명주기 단계에 맞춰 필요한 코드를 작성함으로써, 앱이 예상대로 동작하고 리소스를 효율적으로 관리하며, 사용자 경험을 최적화할 수 있습니다.

액티비티 생명주기는 다음과 같은 주요 상태와 콜백 메서드로 구성됩니다.

  • onCreate(): 액티비티가 처음 생성될 때 호출됩니다. 일반적으로 레이아웃 초기화, 변수 초기화 등의 초기 설정을 수행합니다.
  • onStart(): 액티비티가 사용자에게 보여지기 직전에 호출됩니다.
  • onResume(): 액티비티가 포그라운드에 위치하여 사용자와 상호작용할 수 있는 상태가 되었을 때 호출됩니다. 이 상태에서 앱은 활발하게 동작합니다.
  • onPause(): 다른 액티비티가 포그라운드로 올라오거나 현재 액티비티가 가려질 때 호출됩니다. CPU를 많이 사용하는 작업은 이 메서드에서 중단하고, 데이터를 저장하는 등의 가벼운 작업을 수행해야 합니다.
  • onStop(): 액티비티가 더 이상 사용자에게 보이지 않을 때 호출됩니다. 일반적으로 리소스를 해제하거나 백그라운드 작업을 정리합니다.
  • onRestart(): onStop() 상태의 액티비티가 다시 시작될 때 호출됩니다.
  • onDestroy(): 액티비티가 소멸되기 직전에 호출됩니다. 모든 리소스를 해제하고 종료 작업을 수행합니다.

주의사항: Android 시스템은 메모리 부족 등의 상황에서 onStop()이나 onDestroy()가 항상 호출된다고 보장하지 않습니다. 따라서 중요한 영구 데이터 저장은 onPause() 단계에서 수행하는 것이 좋습니다.

또한, 화면 회전과 같은 구성 변경(Configuration Change)이 발생하면 액티비티는 소멸되고 다시 생성되는 과정을 거칩니다. 이때 데이터를 보존하기 위해서는 별도의 처리가 필요합니다.

생명주기 콜백 메서드 활용

개발자는 필요에 따라 각 생명주기 콜백 메서드를 재정의하여 특정 시점에 원하는 동작을 수행하도록 구현할 수 있습니다. 예를 들어, onResume()에서 애니메이션을 시작하고, onPause()에서 애니메이션을 멈추는 방식으로 앱의 동작을 제어할 수 있습니다.

결론

액티비티와 그 생명주기에 대한 깊이 있는 이해는 안정적이고 사용자 친화적인 Android 앱을 개발하는 데 필수적입니다. 각 생명주기 단계의 특징을 정확히 파악하고, 적절한 시점에 필요한 작업을 수행함으로써 앱의 성능을 최적화하고 예상치 못한 오류를 방지할 수 있습니다.

본 블로그에서 다룬 내용을 바탕으로 Android 앱 개발 여정에 한 걸음 더 나아가시기를 바랍니다.

주요 내용 요약:

  • 액티비티는 사용자 인터페이스를 갖는 단일 화면이며, 앱의 상호작용 단위입니다.
  • 액티비티 생명주기는 액티비티가 생성, 시작, 재개, 일시 중지, 중지, 재시작, 소멸되는 과정을 나타냅니다.
  • 각 생명주기 단계에 대응하는 콜백 메서드를 통해 앱의 동작을 제어하고 리소스를 관리할 수 있습니다.
  • 구성 변경 시 액티비티가 재시작될 수 있음을 인지하고 데이터 보존에 유의해야 합니다.

최근 안드로이드 TV 같은 특정 환경에서 개발을 하고 있습니다. 안드로이드 TV는 2GB 에서 4GB 정도의 특정상황에서 개발을 하고 있습니다. 그렇기에 메모리의 관리와 CPU의 사용을 제어해야 사용자에게 버벅거리지 않는 좋은 UX를 제공할 수 있습니다. 최근에는 여러 액티비티와 프래그먼트가 아닌 한 액티비티에서 Compose로 여러 내비게이션을 구현하는 방식을 선호합니다. 그렇기에 메모리와 CPU의 관리를 위해서는 액티비티 생명주기를 확실히 이해를 하고 넘어가야합니다. 위 영상은 그 이해를 도와줄 것입니다.

최근 JetPack Compose를 공부하다보니 처음보는 메서드를 보았습니다.

CompositionLocalProvider(LocalColor provides color) {
    Composalble3()
}

여기서 LocalColor provides color라는 부분에서 provides라는 메서드가 어떤 역할을 하는지 알수없었습니다.

 

문서를 봐보니 이런식으로 나와 있었습니다.

provides는 infix 함수로, 특정 CompositionLocal에 값을 할당하는 데 사용됩니다. provides 함수는 CompositionLocal에 새로운 값을 연결하여 해당 값이 CompositionLocalProvider의 범위 내에서 사용될 수 있도록 합니다.

 

infix 메서드란?

Kotlin에서 infix 함수는 중위 호출을 허용하는 함수입니다. 이를 통해 함수 호출 시 점(.)과 괄호(()) 없이도 호출이 가능해져 코드가 더 자연스럽고 읽기 쉽게 됩니다. infix 함수는 보통 두 객체를 연결하는 동작을 표현하는 데 유용합니다.

그렇기에

CompositionLocalProvider(LocalColor provides color) {
    Composable3()
}

CompositionLocalProvider(LocalColor.provides(color)) {
    Composable3()
}

이는 동일한 코드입니다.

이밖에도 

// to
val pair = "key" to "value"  // Pair("key", "value")

// until
for (i in 1 until 5) {  // 1, 2, 3, 4 (5는 포함되지 않음)
    println(i)
}

// downTo와 step
for (i in 5 downTo 1 step 2) {  // 5, 3, 1
    println(i)
}

//shl, shr, and, or, xor
val x = 1 shl 2  // 1을 왼쪽으로 2 비트 이동시켜서 4가 됩니다.
val y = x and 0b0001  // 비트 AND 연산 수행

이러한 메서드들이 있습니다.

provides 의 역할은?

Compose에서 provides는 CompositionLocal에 특정 값을 할당하는 역할을 합니다. CompositionLocal은 컴포지션 트리의 하위 컴포저블에 값을 전달하기 위한 컨텍스트와 비슷한 역할을 합니다. provides를 사용하면 CompositionLocalProvider 범위 내의 모든 하위 컴포저블에서 이 값에 접근할 수 있습니다.

val LocalColor = compositionLocalOf { Color.Black }

@Composable
fun MyApp() {
    CompositionLocalProvider(LocalColor provides Color.Red) {
        // 이 범위 내에서는 LocalColor의 값이 Color.Red로 설정됩니다.
        Composable3()
    }
}

@Composable
fun Composable3() {
    val color = LocalColor.current  // 현재 값인 Color.Red를 사용
    Box(modifier = Modifier.background(color)) {
        // 이 Box는 배경색이 Color.Red가 됩니다.
    }
}

참고

https://charlezz.com/?p=46403

 

Compose의 CompositionLocal 이해하기 | 찰스의 안드로이드

컴포저블 함수는 트리(tree)로 구성된다. 이 때 상태는 일반적으로 트리에서 가능한 한 가장 높은 노드에 선언되어야 한다(상태 호이스팅). 그리고 일반적으로 이렇게 선언된 상태는 하위 트리로

charlezz.com

 

+ Recent posts