출처 : https://developer.android.com/guide/platform?hl=ko
안드로이드 운영체제는 위와 같은 아키텍처로 구성되어 있습니다. 이러한 구조 중에서 특별히 더 중요하게 알아두어야 할 부분은 다음의 세 가지입니다.
① 리눅스 커널
② 하드웨어 추상화 레이어(HAL, Hardware Abstract Layer)
③ 안드로이드 런타임(ART, Android Runtime)
안드로이드에 .dex가 사용되는 이유를 이해하려면, JVM과 DVM에대한 이해가 필요합니다.
먼저, JVM은 클래스가 필요할 때마다 동적으로 .class 파일을 읽습니다. 이 때 JVM은 컴퓨터의 메모리를 사용하게 되고 스택 기반으로 opcode(작업코드) 를 읽어서 사용합니다.
반면, DVM은 .dex라는 파일에 모든 클래스 파일들을 변환하여 저장합니다. 즉 하나의 파일에 모든 소스가 있는 셈입니다. 그리고 이러한 dex파일로부터 DVM은 opcode(작업코드) 를 읽어서 사용합니다.
정리하자면, JVM은 필요할 때마다 클래스 파일 중에서 골라 쓰는 셈이고, dex는 하나의 파일에서 관리한다는 것입니다.
그런데, 스택 기반의 가상머신은 컴퓨터의 메모리에서 스택으로 프로그램을 관리하는 반면, 레지스터 기반의 가상머신은 컴퓨터 CPU에 직접 접근하기 때문에 속도 측면에서 더 빠르나, CPU의 한정된 메모리를 사용하기 때문에 메모리 용량이 작다 는 단점이 있습니다.
메모리 용량 측면에서는 스택기반의 가상머신인 JVM이 유리하지만, 속도 측면에서는 레지스터 기반의 DVM이 유리한 것입니다.
지금의 모바일 및 컴퓨터 하드웨어 기술 수준을 생각하면,
굳이 레지스터말고 자바 기반의 JVM을 사용해도 좋았을 것 같은데, 이 이유에 대해서 아직 안드로이드 스튜디오나 구글의 공식 입장을 찾아보진 못했습니다.
그러나, 제 스스로 그 이유를 추론해보자면 안드로이드 OS가 탄생했던 당시의 시대적 배경을 생각하면, 오히려 JVM 보다 DVM을 선택하는 것이 더 합리적이었다고 생각됩니다.
왜냐하면, 초기 모바일 디바이스는 메모리 용량이 그렇게 크지도 않았고, 지금도 안드로이드 앱은 수많은 앱들이 하나의 디바이스에서 빠르게 상호작용하고 동작해야하는 점을 고려해보면, 클래스 로더로 .class 파일을 읽어 들여서 동작하는 JVM보다 컴파일 과정을 한번 더 거치더라도 DVM을 채택하면 빠른 속도도 취하고 안드로이드 앱의 라이프 사이클에 따른 빠른 자원의 관리도 유리한 것으로 보여 JVM보다 DVM이 더 합리적이었을 것 같다는 생각이 들었습니다.
물론, 구글은 아마 이보다 더 많은 이유를 포함하여 OS를 설계하고 개발했겠지만, 제 스스로 찾아 보면서 생각해봤을 때는 이러한 이유로 구글이 JVM이 아닌 DVM을 선택했던 것이 더 합리적이라고 판단했을 것 같습니다.
이러한 안드로이드의 아키텍처에 따라서 모든 클래스 파일들은 최종적으로 .dex 로 컴파일이 됩니다.
그래서, 안드로이드 개발에서 자주 사용하는 jar 파일들은 어떻게 DVM에서 동작하게 되는지 의문이 생길 수 있습니다. 이는 jar 파일도 dx(Dexer) 를 통해 .dex파일로 컴파일되기 때문에 가능합니다. 그렇기에 dx(Dexer)는 안드로이드의 SDK(Software Develop Kit) 의 표준 구성 요소가 되었습니다.
하지만, dex는 앞서 설명한 구조적 한계 때문에 다음과 같은 이슈가 있습니다.
ANR(애플리케이션 응답 없음)의 발생, 즉 너무 큰 .dex 파일을 읽어들임으로 인해 애플리케이션이 일시적으로 중단되는 것입니다.
multidex 기반 애플리케이션은 Android 4.0(API 레벨 14) 미만의 시스템에서는 정상적으로 작동하지 않을 수 있습니다.
참고하면 좋을 사이트 : https://www.boldare.com/blog/differences-between-class-and-dex-files-in-java-android/
API 수준 | 버전명 | 출시연도 |
---|---|---|
1 | Android 1.0 | 2008 |
2 | Android 1.1 | 2009 |
3 | Android 1.5 (컵케이크) | 2009 |
4 | Android 1.6 (도넛) | 2009 |
5 | Android 2.0 (에클레어) | 2009 |
6 | Android 2.0.1 | 2009 |
7 | Android 2.1 (에클레어) | 2010 |
8 | Android 2.2 (프로요) | 2010 |
9 | Android 2.3 (진저브레드) | 2010 |
10 | Android 2.3.3 | 2011 |
11 | Android 3.0 (허니콤) | 2011 |
12 | Android 3.1 | 2011 |
13 | Android 3.2 | 2011 |
14 | Android 4.0 (아이스크림 샌드위치) | 2011 |
15 | Android 4.0.3 | 2011 |
16 | Android 4.1 (젤리빈) | 2012 |
17 | Android 4.2 | 2012 |
18 | Android 4.3 | 2013 |
19 | Android 4.4 (킷캣) | 2013 |
20 | Android 4.4W | 2014 |
21 | Android 5.0 (롤리팝) | 2014 |
22 | Android 5.1 | 2015 |
23 | Android 6.0 (마시멜로) | 2015 |
24 | Android 7.0 (누가) | 2016 |
25 | Android 7.1 | 2016 |
26 | Android 8.0 (오레오) | 2017 |
27 | Android 8.1 | 2017 |
28 | Android 9.0 (파이) | 2018 |
29 | Android 10.0 (Q) | 2019 |
30 | Android 11.0 | 2020 |
31 | Android 12.0 | 2021 |
32 | Android 12.1 | 2022 |
33 | Android 13 | 2022 |
34 | Android 14 DEV | TBD |
안드로이드 앱 개발의 핵심은 컴포넌트입니다. 안드로이드에서 동작하는 프로그램을 보통 APP 또는 어플리케이션이라고 칭합니다.
이러한 안드로이드 앱은 컴포넌트로 구성되어 있는데, 안드로이드 앱은 다음의 4가지 컴포넌트로 구성되어 있습니다.
안드로이드에서는 모든 자바 클래스가 컴포넌트인 것은 아닙니다. 안드로이드에서 말하는 컴포넌트들은 위에 설명한 네 가지 컴포넌트 클래스를 상속받는 자바 클래스를 가르키는 말입니다. 또한, 안드로이드 앱은 컴포넌트 뿐만 아니라 일반 클래스도 사용되며 앱마다 필요한 기능을 구현하고 서비스하기 위해 개발자가 직접 만들거나 도입하여 사용하기도 합니다.
안드로이드 앱 내에서 사용되는 정적 자원들은 리소스를 기반으로 개발합니다. 여기서 리소스란 앱의 레이아웃, 색상 값 등 앱 실행중에 변하지 않는 값들을 의미합니다. 안드이드에서는 이러한 값들을 .xml 파일로 관리합니다.
안드로이드 앱에서 정적인 값들을 담은 xml은 앱 내에서 런타임 시 파싱하여 사용하게 됩니다. 그런데, 이러한 자원들은 .java나 .kt와 같은 자바나 코틀린 클래스로도 관리할 수도 있습니다. 그러나 보통 안드로이드 개발을 하는 데에는 보통 XML로 값을 관리하는 편이며, 안드로이드 스튜디오에서도 이러한 방식을 권장합니다.
만약 리소스를 클래스 파일로 관리하게 되면, 컴파일 시간에 값이 결정되므로, 실행 시간에 추가적인 리소스를 사용하지 않습니다. 반면에, XML 파일은 런타임에 파싱되어야 하므로, 실행 시간에 약간의 오버헤드가 발생 할 수 있습니다.
하지만, 이러한 성능 차이는 무시할 정도로 작아서 실제로는 거의 영향을 미치지 않습니다. 따라서, 안드로이드에서 색상 값과 같은 리소스를 관리하는 것은 개발자의 개발 스타일과 개발 환경에 따라 선택할 수 있는 부분이긴 합니다.
그럼에도 일반적으로는 회사에서는 UX/UI 디자이너와 같이 개발자가 아닌 동료와도 협업하고 소통하기 위해서라도 클래스 파일로 작성하는 것보다 xml 파일로 작성해서 관리하는 것이 더 효율적인 편입니다.
그리고 개발하다 보면 고객의 요청에 따라 수정사항이 발생해도 파일 한 두개의 값만 바꾸어주면 다른 앱들을 수정하지 않아도 관리할 수 있다는 장점이 있어서 안드로이드에서 리소스의 관리는 XML 파일로 별도로 관리하는 것이 권장됩니다.