본격적인 안드로이드 공부 시작...

 

추가 확인 필요한 사항
- 서비스 라이프사이클(foregroud, background, bound)


안드로이드 4대 컴포넌트

- Activity, Service, Broadcast Receiver, Content Provider
- 안드로이드 앱의 필수적인 구성요소이며, 각각은 시스템이나 앱에 들어올 수 있는 진입점
- 각 컴포넌트는 독립적으로 존재, 고유의 기능을 수행하며, 인텐트를 통해 상호작용한다.
- 모든 컴포넌트는 메인스레드(UI스레드)에서 실행된다.

 

1. Activity

- 사용자와 상호작용을 담당하는 인터페이스

- 사용자에게 실제로 보이는 화면을 의미

- 액티비티는 두개 이상 동시에 보일 수 없음

- 어플리케이션은 반드시 하나 이상의 액티비티가 있어야 함

 

- 앱을 실행할땐 앱 전체를 호출한다기보다는 앱의 액티비티를 호출하는 것
- 액티비티는 인텐트를 통해 다른 어플리케이션의 액티비티 호출 가능
- 액티비티는 한개 이상의 view(텍스트/버튼/이미지) or ViewGroup(레이아웃)을 포함

- 액티비티 내에 프래그먼트를 추가해서 화면을 분할시킬 수 있음

 

2. Service

- 주로 background에서 어떠한 작업을 처리하기 위해 사용

    - 액티비티는 사용자와 상호작용한다면 Service는 내부에서 동작
- 다만 항상 그런건 아니고 foreground service/background service로 나뉨

 

1) foreground service

- foreground service는 사용자에게 잘 보이는 작업이고, 서비스가 수행하는 동작을 사용자에게 알릴때 사용

- 사용자가 앱과 상호작용하지 않을때도 계속 실행

- 활성화된 액티비티와 동일한 우선순위

 

다만 애초에 서비스의 주목적이 백그라운드니까 foreground service 동작은 WorkManager를 쓰는게 더 좋다

 

2) backgroud service

- background service는 사용자에게 직접 보이지 않는 작업(주로 서비스를 이 용도로 사용)

- 다만 우선순위가 낮아서 시스템 리소스가 부족하면 강제종료될 수 있음

    - 그러므로 즉각적인 실행이 필요하면 foreground service/WorkManager 사용
- 어플리케이션이 종료되어도 이미 시작된 서비스는 background에서 계속 동작한다.
    - 예를들어 타이머 앱은 타이머 시작 후 앱을 종료해도 시간이 계속 흘러간다

    - 또는 어플리케이션을 사용하면서 파일을 다운로드 받을때 서비스를 사용
- 네트워크와 연동 가능
- 현재 비활성화된 Activity보다 우선순위가 높다.


Activity와 Service는 메인스레드(UI스레드)에서 실행된다

그러므로 서비스에서 일 시키려면 다른 쓰레드 생성해서 일 시켜야한다.

3) bound service

- bound service는 IBinder 인터페이스로 서버-클라이언트 관계처럼 서비스와 상호작용

- 여러 프로세스에서 Bound Service에 바인딩해서 작업 수행

    - 바인딩된 컴포넌트 모두 소멸되면 해당 Bind Service도 소멸

 

3. Broadcast Receiver

- 안드로이드 OS로부터 발생하는 각종 이벤트와 정보를 받고 핸들링하는 컴포넌트
- 대부분 UI는 없고 안드로이드 장비상황을 OS가 감시하다가 이벤트가 발생하면 Broadcast Receiver에게 전달하고, 해당 이벤트에 맞는 동작을 Broadcast Receiver가 수행
- 대부분 UI가 없긴한데 상태표시줄 알림을 생성해서 사용자에게 이벤트가 발생했다고 알리는 동작은 가능

 

- 안드로이드 OS가 보내주는 Broadcast를 받는 방법은 안드로이드 라이브러리에 BroadCastReceiver라는 클래스가 추상클래스로 구현되어 있는데, 이걸 상속받아서 onReceive(context, intent) 함수 오버라이딩하면 된다.

- onReceive() 내에서 if (intent.action == "com.abc.def") 라면 어떤 동작을 한다처럼 인텐트마다 동작 구현할 수 있다.

- BroadCastReceiver를 상속받아 구현한 브로드캐스트 클래스를 AndroidManifest.xml에 receiver로 등록하고, 그 receiver내에서 어떤 인텐트들을 받을지 나열해두면 운영체제가 broadcast 보낼 때 해당 앱에서 그 인텐트를 받는지 보고 동작을 수행한다.

 

4. Content Provider

- 안드로이드에서는 각 앱이 자신만의 샌드박스를 가지기 때문에 A앱이 B앱을 절대 읽을 수 없다

    - 그래서 데이터 공유를 하려면 공식적인 창구가 필요하고 그게 Content Provider

- 즉, 어플리케이션 간 데이터 관리 및 다른 어플리케이션의 데이터를 제공하는데 사용되는 컴포넌트

 

- 작은 데이터는 intent로 어플리케이션간 공유할 수 있지만, 음악/사진같은 용량 큰 파일을 Content Provider로 공유
- 데이터 관리는 SQLite DB/Web/파일 입출력 방식으로 관리하며 read/write는 권한이 있어야 접근 가능해서 현재 실행중인 어플리케이션에 접근 못하게 하거나, 원하는 일부 데이터만 접근 허용하는 등의 동작 가능

 

앱 처음 설치할때 전화, 사진에 접근 권한 요청 이런거 뜨는게 이게 Content Provider가 접근해야해서 그렇다.

 

클라이언트-서버 구조처럼 사용하며 Content Provider(서버)가 데이터를 가지고 있는 DB의 역할이고 Content Resolver(클라이언트)가 데이터를 요청하는 앱이 된다

요청은 uri를 사용한 쿼리로 한다.

 

코드상 구현

uri에 content://로 시작하는 문구를 넣고 쿼리를 날린다.

ContentProvider 클래스를 상속받아서 onCreate, query, insert, update, delete 등의 함수를 오버라이딩해서 사용한다.
진짜 db에 뭐 요청하는 느낌처럼 쓸 수 있다.

A앱에서 뭔가 insert하고 다른데서 query로 get하는 모양새가 된다.
보통 insert하는 앱을 Data Provider, query로 get하는 앱을 Data Consumer라고 한다.


정확하게는 Content Provider가 데이터를 보관하는건 아니다.

A앱에서 본인의 데이터를 가지고 있고, 그 데이터에 접근할 수 있는 인터페이스를 uri 형태로 만들어 진입로를 Content Provider에 저장해두는 것이다.

- 진입로는 "content://com.abc.def"같은 형태

그럼 B앱에서 "content://com.abc.def"로 query 호출하면 안드로이드OS가 A앱의 프로세스를 띄워서 데이터를 가져다가 B앱에 준다

 

코드 사용 예시 insert하는쪽과 query하는 쪽 둘 다 좀 적어두면 좋을 듯

 

5. Intent

- 컴포넌트간에 통신 수단

    - 컴포넌트에 Action, Data 등을 전달
    - 주로 가장 많이 사용되는건 화면전환
- Intent로 다른 어플리케이션의 컴포넌트를 활성화 시킬 수 있음

 

- Intent이름은  "VIT_" 형태의 문자열이나 "com.abc.dce"같은 역순uri같은 문자열로 주로 쓴다

단순한 문자열은 아니고 Intent의 멤버변수들이 있다.

    - action : "com.abc.def"같은 문자열이며 무엇을 할 것인가를 의미하는 함수명같은 개념
    - data : content://contacts/people같은 어떤 데이터를 대상으로 할 것인가의 개념
    - category : 문자열 리스트를 전달하면 되고 어떤 환경에서 실행되어야 하는가의 개념

                       앱 목록에 노출할지, 웹브라우저에서 실행가능하게 할지
    - extras : String-Object 형태의 map이며 intent와 함께 전달할 매개변수들을 넣는 곳

val intent = Intent("com.abc.def")
intent.putExtra("name", "abc")
intent.putExtra("width", 10.5)
sendBroadcast(intent)

//위처럼 보내고 onReceive에서 아래처럼 사용

if (intent.action =- "com.abc.def") {
    val name = intent.extras?.getString("name")
    val width = intent.extras?.getDouble("width")
}

안드로이드 액티비티의 생명주기(Life Cycle)

- Activity는 클래스다.
- 액티비티는 안드로이드 4대 컴포넌트 중 하나
- UI와 가장 밀접한 관련
- 앱은 하나 이상의 액티비티가 서로 연결된 형태로 구성

 

1.  액티비티 예시

- 카카오톡 실행 시 처음 나오는 카카오톡 로고가 하나의 액티비티
- 그 후 진입되는 친구목록이나 채팅목록 화면도 별도의 하나의 액티비티
- 카카오톡을 내리고 유투브를 켜면 유투브 액티비티가 보이게 됨
- 이렇게 액티비티가 전환될때마다 각자 생명주기에 따라 호출되는 함수가 있음

 

2. 액티비티 함수

- onCreate() : 최초 앱 실행 시 단 한번만 호출, 주로 초기화 관련 작업 수행
- onStart() : 액티비티가 화면에 표시되기 직전에 호출(화면에 진입할때마다 호출되어야 하는 작업 구현)
- onResume() : 액티비티가 화면에 표시된 직후에 호출(액티비티가 포커스된 상태)
- onPause() : 액티비티가 보여지지 않은 직후에 호출(포커스를 잃은 상태), 저장해야하는 데이터가 있다면 여기서 저장(단 다른 액티비티가 보여지게 되므로 너무 무거운 작업하면 안됨)
- onStop() : 액티비티가 완전히 보이지 않게 됐을때
- onDestroy() : 액티비티가 종료/앱 프로세스가 종료됐을때

- onRestart() : onStop() 상태인데 해당 액티비티로 전환되서 보여지게되면 onRestart() 호출하고 바로 onStart()호출

다른 액티비티(불투명하고 화면 꽉채우는게)가 올라오게되면 onPause()랑 onStop() 연달아서 둘 다 호출된다.
그러니까 onPause()만 호출하고 onStop() 호출 안하는 케이스는 투명한 새로운 액티비티 호출하면 된다.

 

3.  다이얼로그

다이얼로그는 액티비티의 일부이다.
그래서 액티비티 위에 다이얼로그가 올라와서 화면 가려지면 onPause가 호출되어야할것같지만 액티비티가 다른 액티비티로 가려진게 아니라서 호출되지 않는다.

 

4. 프래그먼트

- 이건 일단 개념은 보긴 할건데 우리 프로젝트는 프래그먼트 일부러 안쓰고 액티비티만 쓰게 구현해놔서... 차후 확인 예정
- 앱 UI의 재사용 가능한 부분(모듈성/재사용성)
- 자체 레이아웃 정의/관리하고 자체 생명주기를 가지며, 자체입력이벤트 처리 가능
- 단독으로 실행불가능하고 액티비티나 다른 프래그먼트에서 호스팅해야함
- 액티비티가 onStart 상태에 있는 동안 프래그먼트를 추가/교체/제거할 수 있다.