안드로이드 주요 특징 및 아키텍처 소개
안드로이드의 주요 기능
- 애플리케이션 프레임워크를 통해서 제공되는 API를 사용함으로써 코드를 재사용하여 효율적이고 빠른 애플리케이션 개발 가능
- 모바일 기기에 최적화된 달빅(Dalvik) 또는 아트런타임(ART) 제공
- 2D 그래픽 및 삼차원 그래픽을 최적화하여 표현
- 각종 오디오, 비디오 및 이미지 형식을 지원
- 모바일 기기에 내장된 각종 하드웨어 지원
- 이클립스 IDE 또는 Android Studio를 통해서 강력하고 빠른 개발 환경 제공
- 모바일용 데이터베이스인 SQLite를 제공
- 롤리팝(5.0)부터는 다양한 안드로이드 기기를 통합 지원
- 누가(7.0)부터는 가상현실 지원 및 3D 게임, 다중 창 열기 지원
- 오레오(8.0)부터는 PIP, 알림, 자동 채우기, 배터리 강화 등을 지원
- 파이(9.0)부터는 실내 위치 추적, 향상된 알림, 멀티 카메라, 인공지능 확장 등의 업데이트
- Android 10(Q) : 온디바이스 AI, 라이브 캡션, 스마트 재생, 청각 보조
- Android 12 : 새롭게 디자인 된 알림창, 실키홈, 얼굴 인식 자동 회전
안드로이드 구조
- 응용 프로그램 : 안드로이드 스마트폰에서 사용할 수 있는 일반적인 응용 프로그램.
- 응용 프로그램 프레임워크 : 안드로이드 API가 존재하는 곳.
- 라이브러리 + 안드로이드 런타임 :
=> 시스템 라이브러리는 시스템 접근 때문에 JAVA가 아닌 C로 작성. 성능이 뛰어나며 세밀한 조작이 가능함.
=> 안드로이드는 JAVA 문법으로 프로그래밍하지만 JAVA 가상 머신을 사용하지 않고 이곳의 달빅 가상 머신이나 아트런타임을 이용함. - 리눅스 커널 : 하드웨어 운영과 관련된 저수준의 관리 기능이 들어있음.
안드로이드 개발 환경을 구축하면 가상의 안드로이드 장치인 AVD(Android Virtual Device) 제공.
개발 환경의 구성
- 구조 이해 : Android Studio를 실행해 코딩,수정을 통해 앱을 개발. 코딩된 결과는 AVD에 출력하고, 개발자는 그 결과를 확인.
응용 프로그램 개발 : JAVA 사용 / 초중급 / SDK / 일반 응용 프로그램 개발
시스템 응용 프로그램 개발 : C, C++ 사용 / 중고급 / NDK / 고수준의 응용 프로그램 개발
하드웨어 제어 및 커널 관련 : C, C++ 사용 / 고급 / PDK / 하드웨어 수준의 강력한 프로그램 개발
앱 개발 구성 요소
- 애뮬레이터 혹은 디바이스 : 안드로이드 스튜디오에서 개발한 앱 테스트
- adb 프로그램 : 안드로이드 스튜디오를 실행하면 자동으로 실행되어 [애뮬레이터 / 디바이스]로 전송되어 실행
- adbd 프로그램 : 안드로이드 디바이스 내부에서 adb 서버와의 통신을 담당
- Run 메뉴 : [안드로이드 플러그인] -> [adb 서버] -> [adbd] -> [애뮬레이터 / 디바이스]로 전송되어 실행
- 디버거 : 프로그램 버그를 찾기 위한 소프트웨어 앱을 직접 사용 또는 안드로이드 스튜디오에 내장
객체지향 프로그래밍 이해
클래스
- 클래스(class)는 변수(필드)와 함수(메소드)로 구성
- 메소드 오버로딩 : 클래스 내에서 메소드의 이름이 같아도 파라미터의 개수나 데이터형만 다르면 여러 개의 선언이 가능
- 정적 필드(static field) : 클래스 자체에서 사용되는 변수.
- 정적 메소드(static method) : 메소드 앞에 static을 붙여 사용. 인스턴스 없이 "클래스명.메소드명()"으로 호출되어 사용.
- 상수 필드(constant field) : 정적 필드에 초기값을 입력하고 final을 앞에 붙임.
클래스의 상속(inheritance)
- 기존 클래스를 그대로 물려받으면서 필요한 필드나 메소드를 추가로 정의
- 수퍼 클래스(부모 클래스) / 서브 클래스(자식 클래스)
추상(abstract) 클래스 : 인스턴스화를 금지하는 클래스
=> 클래스 앞에 abstract 써서 사용
추상 메소드 : 메소드 본체가 없는 메소드
=> 메소드 앞에 abstract 써서 사용
추상 메소드를 포함하는 클래스는 추상 클래스로 지정해야 함.
인터페이스(Interface)
- class 키워드 대신 interface 키워드를 사용해서 정의
- 내부에는 추상 메소드를 선언
- 클래스에서 인터페이스를 지원 받아서 완성할 때 implements 사용
- Java는 다중 상속을 지원하지 않지만, 인터페이스를 사용해서 다중 상속과 비슷하게 작성할 수 있음.
( static class Me extends Mother implements Father )
패키지(Package)
- 클래스와 인터페이스가 많아지면 관리가 어려워 패키지 단위로 묶어서 관리
- 사용자가 생성한 클래스가 포함될 패키지는 *.java 파일 맨 첫 행에 지정
제네릭스(Generics)
- 데이터 형식의 안전성을 보장하는 데 사용
- 뿐 아니라 <Integer>, <Double>, 사용자가 정의한 클래스형에 사용
프로젝트와 액티비티
일반적인 애플리케이션 작성 절차
- 사용자 인터페이스 작성 (XML)
- 자바 코드 작성 (JAVA)
- 매니페스트 작성 (XML)
패키지 폴더의 설명
- java : 자바 소스 파일들이 들어있는 폴더이다. 폴더 안의 'kr.co.company.abcd'는 패키지명이다.
- Gradle Scripts : Gradle은 빌드 시에 필요한 스크립트이다.
=> build.gradle (Module.app) : 빌드 스크립트 핵심 파일.
=> local.properties : 컴파일 되는 SDK의 경로가 들어가 있음.
=> gradle.properties : JVM 관련 메모리가 설정되어 있음. - res : 각종 리소스(자원)들이 저장되는 폴더이다.
=> drawable : 해상도 별로 아이콘 파일들이 저장된다.
=> layout : 화면의 구성을 정의한다.
=> values : 문자열과 같은 리소스가 저장된다.
=> menu : 메뉴 리소스들이 저장된다. - maifest : XML 파일(AndroidManifest)로 앱의 전반적인 정보 즉 앱의 이름이나 컴포넌트 구성과 같은 정보를 가지고 있다.
- generatedJAVA 폴더 : 버전 3.2부터 제공되는 폴더로 시스템 내부적으로 사용됨.
안드로이드 4대 컴포넌트
- 액티비티(Activity) : 화면을 구성하는 가장 기본적인 컴포넌트
- 서비스(Service) : 액티비티와 상관없이 백그라운드에서 동작하는 컴포넌트
( 서비스 생성 -> 서비스 시작 -> 서비스 종료) - 브로드캐스트 리시버(Broadcast Receiver) : 문자 메세지 도착, 배터리 방전, SD 카드 탈부착, 네트워크 환경 변화 등이 발생하면 전체 응용프로그램이 들을 수 있도록 방송 신호를 보냄.
- 콘텐트 프로바이더(Content Provider) : 응용프로그램 사이에 데이터를 상호 공유하기 위한 컴포넌트
=> 콘텐트 포로바이더의 정보를 제공하는 방법으로는 URI(Uniform Resource Identifier)가 있음
View 계층도
- Object -> View -> ViewGroup, TextView, ImageView, ProgressBar
=> ViewGroup -> Linear / Relative / Frame / Grid Layout, AdapterView, ToolBar
=> TextView -> EditText, Button
=> ImageView -> ImageButton
- 안드로이드 화면에서 실제로 사용되는 것들은 모두 View 클래스 상속
- 뷰 클래스는 다른 말로 '위젯'이라고도 함.
- 다른 위젯을 담을 수 있는 위젯은 레이아웃임.
- 레이아웃은 ViewGroup 안에 존재.
View
- 뷰(View) : 화면에 보이는 각각의 것들(버튼, 텍스트 등등). 흔히 컨트롤(Control)이나 위젯(Widget)이라 불리는 UI 구성 요소
- 뷰 그룹(View Group) : 뷰들을 여러개 포함하고 있는 것. 뷰 그룹도 뷰에서 상속하여 뷰가 됨. 즉, 위의 뷰는 버튼, 텍스트 뿐만 아니라 이것들을 포함하는 눈에 보이지 않는영역(레이아웃 ..)을 포함한다.
- 위젯(Widget) : 뷰 중에서 일반적인 컨트롤의 역할을 하고 있는 것. (버튼, 텍스트 ..)
- 레이아웃(Layout) : 뷰 그룹 중에서 내부에 뷰들을 포함하고 있으면서 그것들을 배치하는 역할을 하는 것.
=> 레이아웃도 뷰이기 때문에 레이아웃 안에 레이아웃을 포함시킬 수 있음
뷰는 뷰 태그와 속성으로 구성된다.
- match_parent : 뷰그룹에 남아 있는 여유 공간을 채움
- wrap_content : 뷰에 들어 있는 내용물의 크기에 따라 뷰의 크기가 결정됨
- 크기 값 지정 : 크기를 고정된 값으로 직접 지정하고 싶을 때 사용함
패딩이란 뷰의 경계아 뷰의 내용물 사이의 간격.
마진이란 자식 뷰 주의의 여백.
이미지버튼 및 이미지뷰의 XML 속성
- src : 이미지의 경로를 나타냄
- maxHeight/maxWidth : 이미지의 크기를 지정
- scaleType : 이미지의 확대/축소 방식 지정
- 그림 파일이 [res]-[drawble] 폴더에 있어야 사용 가능
렐러티브 레이아웃(RelativeLayout)
렐러티브 레이아웃은 레이아웃 내부에 포함된 위젯을 상대적인 위치로 배치
=> 다른 위젯의 상대 위치에 배치
=> 각 속성의 값은 다른 위젯의 id를 지정하면 됨
=> "@+id/기준 위젯의 아이디"와 같은 형식으로 지정으로 사용
테이블 레이아웃(TableLayout)
- 주로 위젯을 표 형태로 배치할 때 사용
- 와 함께 사용되는데, 의 개수가 바로 행의 개수가 됨
- 열의 개수는 안에 포함된 위젯의 수로 결정
- layout_column : 지정된 열에 현재 위젯을 표시하라는 의미
- stretchColumns : 지정된 열의 폭을 늘리라는 의미
- stretchCoulmns = "*" : 각 셀을 같은 크기로 확장, 전체 화면이 꽉 차는 효과
그리드 레이아웃(GridLayout)
- 테이블레이아웃처럼 위젯을 표 형태로 배치할 때 사용하지만, 좀 더 직관적임.
- Android 4.0부터 지원
프레임 레이아웃(FrameLayout)
- 단순히 레이아웃 내의 위젯을 왼쪽 상단부터 겹쳐서 출력
- 프레임레이아웃 자체로 사용하기보다는 탭 위젯 등과 혼용해서 사용할 때 유용
- foreground : 프레임레이아웃의 전경 이미지를 저장
- foregroudGravity : 전경 이미지의 위치를 저장
컨스트레인 레이아웃(ConstraintLayout)
- 뷰의 연결점(Archor Point)와 대상(Target)을 연결
- 부모 레이아웃(Parent Layout) : 자신을 감싸고 있는 레이아웃
- 핸들(Side Constraint Handle)이라고 불리는 연결점은 마우스 커서로 조정
- 꼭 필요한 제약 조건은 두개
인텐트
인텐트(Intent) : 안드로이드 4대 컴포넌트가 상호 간에 데이터를 주고 받기 위한 메시지 객체. 명시적 인텐트와 암시적 인텐트로 구분.
명시적 인텐트의 데이터 전달
명시적 인텐트 : 다른 액티비티의 이름을 명확히 지정할 때 사용하는 방법
Intent intent = new Intent(getApplicationContext(), SecondActivity.class);
startActivity(intent);
메인 액티비티에서 인텐트에 데이터를 실어서 넘긴 후, 세컨트 액티비티에서 받은 데이터를 처리
양방향 액티비티와 데이터의 전달
메인 액티비티에서 세컨드 액티비티로 데이터를 넘긴 후에, 다시 세컨드 액티비티에서 메인 액티비티로 데이터를 돌려주는 경우.
암시적 인텐트(Implicit Intent, 묵시적 인텐트)
약속된 액션(Action)을 지정하여 안드로이드에서 제공하는 기존 응용 프로그램을 실행하는 것.
전화 거는 것을 예로 들면 전화번호를 인텐트로 넘긴 후에 전화 걸기 응용 프로그램이 실행되는 것과 같음.
액티비티 생명주기
- 액티비티의 생성부터 소멸까지의 주기를 뜻함.
- 안드로이드 응용 프로그램은 화면이 작아 동시에 여러 개의 액티비티(화면)가 나올 수 없음.
- 앞에 나오는 화면 하나만 활성화된 상태이고 나머지는 모두 비활성화된 상태로 남게 됨.
onCreate() - 액티비티를 생성할 때 실행. 전체 생명 주기 동안 한 번만 실행.
onStart() - 액태비티가 사용자에게 표시된다. (앱은 액티비티를 포그라운드에 보내 상호작용할 수 있게 한다.)
onResume() - onStart()로 앱이 표시되고, 사용자가 앱과 상호작용하며 어떤 이벤트가 발생하여 앱에서 포커스가 떠날 때까지 앱이 머무르는 상태
=> 예를 들어 전화가 오거나, 다른 액태비티로 이동할 때 꺼짐
onPause() - 사용가자 액티비티에서 떠나는 첫 번째 신호. 액티비티가 소멸되는 것은 아니지만, 액태비티가 포그라운드에 있지 않게됨.(다만 사용자가 멀티 윈도우 모드에 있을 경우 여전히 표시) 즉, 액태비티가 일시중지 상태가 됨.
onStop() - 액태비티가 사용자에거 더 이상 표시되지 않으면 onStop 상태에 들어감. 예를 들어 새로 시작된 액티비티가 화면 전체를 차지할 경우 적용. 모든 기능 정지되고 실행이 종료.
onDestroy() - 액티비티가 소멸되기 전에 호출. 액티비티가 종료.
로그캣 함수(LogCat)
android.util.Log.d("태그", "메시지") : Debugging 용도로 남기는 로그
옵션 메뉴(Option menu)
안드로이드의 메뉴는 옵션 메뉴와 컨텍스트 메뉴로 구분.
- 메뉴 폴더 생성 및 메뉴 XML 파일 생성, 편집 : 메뉴 코딩
- JAVA 코딩 : onCreateOptionMenu() 메소드 오버라이딩 : 메뉴 파일 등록
- JAVA 코딩 : onOptionsItemSelected() 메소드 오버라이딩 : 메뉴 선택 시 작동할 내용 코딩
컨텍스트 메뉴(Context Menu)
레이아웃 또는 버튼, 에딧텍스트 등의 위젯을 롱클릭하면 나타남. Window의 팝업창과 비슷.
- 메뉴 폴더 생성 및 메뉴 XML 파일 생성, 편집 : 메뉴 코딩
- JAVA 코딩 : onCreate() 안에 registerForContextMenu()로 등록 : 메뉴를 사용할 위젯 등록
- JAVA 코딩 : onCreateContextMenu() 메소드 오버라이딩 : 메뉴 파일 등록
- JAVA 코딩 : onContextItemSelected() 메소드 오버라이딩 : 메뉴 선택 시 작동할 내용 코딩
프래그먼트
레이아웃 안에 부분 화면으로 레이아웃을 넣을 수 있다.
태블릿과 같이 큰 화면에서는 한 화면에 여러 부분화면을 넣는 것이 효율적임.
프래그먼트는 부분화면을 독립적으로 만들어주며 액티비티를 그대로 본떠 생성
하나의 액티비티에 하나의 프래그먼트를 전체 화면으로 보여주면 시스템과 관계없이 전체 화면을 전환하는 효과를 만들 수 있음.
프래그먼트는 액티비티 위에 올라가야 프래그먼트로 동작함.
인플레이션을 위한 별도의 콜백 메소드를 제공함.
프래그먼트 의사소통 방식
프래그먼트 생명주기
onAttach() - 프래그먼트가 액티비티와 연결되어 있던 경우 호출 ( 여기에서 액티비티가 전달됨)
onCreate() - 프래그먼트를 생성할 때 시스템에서 호출.
onCreateView() - 프래그먼트와 연결된 뷰 계층을 생성하기 위해 호출
onActivityCreated() - 액티비티의 onCreat() 메서드가 반환할 때 호출
onStart()
onResum()
onPause() - 변경사항을 커밋한다.
onStop()
onDestroyView() - 프래그먼트와 연결된 뷰 계층이 제거되는 중일 때 호출
onDestroy()
onDetach() - 프래그먼트가 액티비티와 연결이 끊어지는 중일때 호출
액티비티와 프래그먼트의 수명 주기에서 가장 중대한 차이점은 해당되는 백 스택에 저장되는 방법에 있습니다. 기본적으로 액티비티는 정지되면 시스템에서 관리하는 액티비티의 백 스택에 들어갑니다(작업 및 백 스택에서 설명하였듯이 사용자는 Back 버튼을 눌러서 액티비티로 돌아갈 수 있습니다). 하지만 프래그먼트는 이를 제거하는 트랜잭션에서 addToBackStack()을 호출하여 인스턴스를 저장하라고 명시적으로 요청할 경우에만 호스트 액티비티에서 관리하는 백 스택으로 들어갑니다.
비동기 처리 쓰레드
메인 액티비티
- 애플리케이션이 실행될 때 하나의 프로세스에서 처리
- 이벤트를 처리하거나 필요한 메소드를 정의하여 기능을 구현하는 경우에도 동일한 프로세스 내에서 실행
=> 문제점
- 대기 시간이 길어지는 네트워크 요청 등의 기능을 행할 때는 화면에 보이는 UI도 멈춤 상태로 있게 됨.
=> 해결방안
- 하나의 프로세스 안에서 여러 개의 작업이 동시 수행되는 멀티 스레드 방식을 사용.
멀티 스레드
- 같은 프로세스 안에 들어 있으면서 메모리 리소를 공유하게 되므로 효율적인 처리가 가능.
- 동시에 리소스를 접근할 경우 데드락(DeadLock) 발생.
서비스 vs 스레드
서비스 사용 : 백그라운드 작업은 서비스로 실행하고 사용자에게는 알림 서비스를 이용해 알려줌. 만약 메인 액티비티로 결과값을 전달하고 이를 이용해 다른 작업을 수행하고자 한다면 브로드캐스팅을 이용하거나 하여 결과값을 전달할 수 있음.
스레드 사용 : 스레드는 동일 프로세스 내에 있기 때문에 작업 수행의 결과를 바로 처리할 수 있음. 그러나 UI 객체는 직접 접근할 수 없으므로 핸들러(Handler) 객체를 사용함.
JAVA에서의 스레드
메인 스레드 : 애플리케이션 객체인 액티비티, 브로드캐스트 수신자 등과 새로 만들어지는 윈도우를 관리하기 위한 메시지 큐(Message Queue)를 실행함.
메시지 큐(Message Queue) : 순차적으로 코드를 수행함
핸들러(Handler) : 메시지 큐를 이용해 메인 스레드에서 처리할 메시지를 전달하는 역할을 담당함. 특정 메시지가 미래의 어떤 시점에 실행되도록 스케줄링 할 수 있음.
비동기 처리 스레드
- obtainMessage() : 호출의 결과로 메시지 객체를 리턴받게함.
- sendMessage() : 메세지 큐에 넣음.
- handleMessage() : 메소드에 정의된 기능이 수행됨. 코드가 수행되는 위치는 새로 만든 스레드 아닌 메인 스레드가 됨.
스레드에서 데이터를 주고 받는 2가지 방식
핸들러 클래스 : 메시지 전송 방법 이외에 Runnable 객체를 실행시킬 수 있는 방법을 제공함.
Runnable 객체 : 새로 만든 Runnable 객체를 핸드러의 post() 메소드를 이용해 전달해 주기만 하면 이 객체에 정의된 run() 메소드 내의 코드들은 메인 스레드에서 실행됨.
프레퍼런스(Preference)
- 안드로이드에서 가장 간단한 데이터 저장 기법
- 키(key)와 값(value) 형식으로 기본형 데이터의 저장과 읽기 가능
- 기본형 데이터 : 부울, 정수, 실수, 문자열, 문자열 집합
- getSharedPreferences()로 SharedPreferences 객체 생성
- SharedPreferences 객체는 edit()을 호출하여 SharedPreferences.Editor 객체를 얻음
- SharedPreferences.Editor 객체는 putBoolean(), putInt() ..를 호출하여 키와 값을 전달
- SharedPreferences.Editor 객체는 apply() 또는 commit()을 호출하여 키와 값을 저장
내부 저장소(Internal Storage)
- 안드로이드 기기의 내장 메모리 영역
- /data 디렉터리 내부에 존재
- /data/data/패키지명 디렉터리
- 개별 앱의 전용 공간이며 다른 앱은 물론이고 기기 사용자도 임의 접근 불가
- 사용자가 기기에서 앱을 제거하면 /data/data/패키지명 디렉터리도 자동 삭제
내부 저장소 파일 생성 및 데이터 저장 절차
- openFileOutput()을 호출하여 표준 자바의 FileOutputStream 객체 얻기
FileOutputStream openFileOutput(String name, int mode)
- FileOutputStream 클래스의 write() 메서드로 데아터 저장
- FileOutputStream 클래스의 close() 메서드로 스트림 닫기
내부 저장소 파일 열고 데이터 읽는 절차
- openFileInput()을 호출하여 표준 자바의 FileOutputStream 객체 얻기
FileInputStream openFileOutput(String name)
- FileOutputStream 클래스의 read() 메서드로 데이터 읽기
- FileOutputStream 클래스의 close() 메서드로 스트림 닫기
외부 저장소(External Storage)
내부 저장소를 제외한 사용자 데이터 저장 공간
- 외부 저장소에 대한 접근 권한 얻기
- 외부 저장소가 사용 가능한지 확인
- 외부 저장소에 파일을 생성하여 데이터 저장. 혹은, 기존 파일을 열어서 데이터 읽기.