C 언어
Cpp 언어
Kotlin
Android App
알고리즘
Git/CI/CD
Android Foundation

Android 4대 Component
1. Activity
 - UI를 담당하는 컴포넌트
 - Activity 내에는 여러 Fragment를 표시하는 것 가능
 - 각 Activity는 Manifest에 등록되어 있어야 사용 가능

2. Service
 - UI 없이 백그라운드에서 동작하는 컴포넌트 (단, 최근에는 Notification 등록하여 foreground로 동작)
 - 앱이 종료되더라도 계속 살아서 동작함

3. Content Provider
 - 앱 간 복잡한 DB나 파일을 주고받을 때 사용하는 컴포넌트
 - 제공자는 데이터 형식과 URI 포맷을 설계 후 ContentProvider 클래스를 구현하고,
   제공받고자 하는 대상은 ContentResolver를 통해 Query를 요청하여 데이터를 제공받음.

4. Broadcast Receiver
 - Broadcasting되는 다양한 정보를 전달받기 위한 컴포넌트
 - 정적/동적 등록 가능하며, 시스템 관련 일부 정보(Screeon On/Off 또는 들은 동적 등록했을 경우에만 수신 가능함.
 - IntentFilter를 등록해서 관심있는 정보만 전달받아 처리할 수 있음.


Android 추가 Component
1. Intent
 - 안드로이드 컴포넌트 간 통신을 위해 사용되는 역할을 함.
 - 어떤 패키지를 대상으로 한 것인지, 어떤 동작을 요청하는 것인지, 추가적인 데이터 등까지 포함하여 전송할 수 있음.
 - 명시적 인텐트와 암시적 인텐트가 있으며, 명시적 인텐트는 보통 대상 Package나 Class를 지정하여 호출하고 암시적 인텐트는 Action과 Category를 통해 호출함.
 - Intent 속성은 대략 아래와 같다.
    1) Action
        호출 대상에게 요청하거나 알리기 위한 행동을 의미함. (예 : ACTION_MAIN - 메인 액티비티 실행을 요청, ACTION_SCREEN_ON - 화면이 켜졌음을 알림)
    2) Category
        Action에 대한 부가 타입으로, 세부적인 분류를 위한 정보임. (예 : ACTION_MAIN에 대해 CATEGORY_BROWSABLE 카테고리가 추가되면 브라우징 가능한 앱에 대해 메인 액티비티 실행을 요청)
    3) Extras
        요청한 작업을 수행하는 데 필요한 추가 정보가 담긴 키-값 쌍.
    4) Flags
        인텐트가 어떠한 방식으로 처리되어야 하는지 알려주기 위한 특수 값. (예 : FLAG_ACTIVITY_NEW_TASK 가 붙으면 새로 실행되는 Activity는 새로운 Task에서 실행됨)
    5) 기타 package, data, type, scheme 등 추가 속성들이 있다.
 - PendingIntent
   PendingIntent는 다른 컴포넌트가 나중에 자신의 권한을 허가하여 Intent를 실행할 수 있도록 해 주는 역할을 한다.
   Intent를 만들어서 다른 컴포넌트에게 주면, 다른 컴포넌트는 나중에 요청자의 권한을 통해 Intent를 수행할 수 있다.
   
2. Context
 - 현재 어플리케이션 환경과 상태에 대한 정보를 담고 있으며, 
   어플리케이션 리소스나 클래스에 액세스하거나 
   안드로이드 시스템 서비스에서 제공하는 API를 호출 할 수 있는 기능을 가진 클래스이다.
 - 크게 5가지 타입으로 나뉘며, 자세한 것은 아래 표를 참조하자.
    1) Application Context
        Application 당 1개로 Singleton Instance를 가지고 Application LifeCycle과 함께 동작한다.
        만약 Application 내에서 Singleton으로 생성되는 Class가 Context를 참조해야 한다면 해당 Context를 가져오는 것이 맞다.
    2) Activity Context
        Activity 생성 시 만들어지는 Context로, Activity 자신이 Context를 상속받음.

        Application Context를 상속받아 생성되며 Activity LifeCycle과 함께 동작한다.
        GUI 관련 작업이 필요한 경우 Activity Context를 사용해야 한다. (ApplicationContext가 지원하지 않는 경우 있음)
    3) Service Context
        Service 생성 시 만들어지는 Context로, Service 자신이 Context를 상속받음.
        Application Context를 상속받아 생성되며 Service LifeCycle과 함께 동작한다.
    4) ContentProvider Context
        자기 자신이 Context는 아니며, getContext()를 통해 접근 가능하다.
        Application Context를 상속받아 생성되며, 하나의 Application 안에서 Singleton 객체이다.
    5) BroadcastReceiver Context
        자기 자신이 Context는 아니며, onReceive() 시 메소드 인자로 전달된다. ReveiverRestrictedContext 를 상속받아 생성되며,
        이 Context를 통해서는 broadcastReceiver 추가 등록이 막혀 있는 등 기능 제약이 있다.
       
 - Context를 얻는 방법은 아래와 같이 3가지가 있다.
    1) getApplicationContext() : Application Context를 리턴한다.
    2) getContext() : 현재의 Context를 리턴한다.
    3) getBaseContext() : ContextWrapper를 통해 특정 메소드 등이 Override된 context가 전달되었을 경우가 있다.
                                          이 때, Override된 context가 아닌 원본 Context를 접근하고자 할 때 사용한다.
                                          즉, ContextWrapper의 원본 대상 Context를 리턴한다.
                                          (일반적으로는 getContext()와 거의 동일함)



Activity LifeCycle



* Activity가 onDestroy()가 아니고 onStop()까지만 동작하는 시나리오라면
   onStop() 다음에 무조건 onSaveInstanceState()가 호출됨.
   => onPause() -> onStop() -> onStateInstanceState() 호출된 상태로 기다렸다가, 다시 돌아올때 configuration 변화가 없었다면
        onRestart() -> onStart() -> onResume()으로 됨.
* Activity가 Back 키를 통해서 종료(onDestroy()가 호출)되는 경우에만 onSaveInstanceState() 호출 안 됨.
* configuration이 변경(로테이션 변경 등)됬을 때는 onDestroy()가 호출되지만
   이 경우에만 다시 create start되면서 onRestoreInstanceState()가 호출됨.
   => onPause() -> onStop() 까지 간 다음에 onSaveInstanceState() -> onDestroy() 호출된 다음
   => onCreate() -> onStart() 다음에 onRestoreInstanceState() -> onResume() 순으로 호출 됨.

* 정리
    1) onSaveInstanceState() : Activity가 완전 종료되는 Case를 제외하고, onStop() 다음에 무조건 호출됨
    2) onRestoreInstanceState() : Activity가 Configuration 변경(로테이션, 화면 크기 등)으로 인해 Re-Create되는 경우에만 onStart() 다음에 호출됨.

   

만약 A Activity가 B Activity를 실행시키면?
A는 onPause()됨
B가 onCreate()..onResume()까지 됨
A가 onStop(), onSaveInstanceState() 호출됨.
이 순서는 일단 현재로써는 무조건이라고 봐야 함.
[A Activity] onPause()
[B Activity] onCreate()
[B Activity] onStart()
[B Activity] onResume()
[A Activity] onStop()
[A Activity] onSaveInstanceState()
 * 정리
    A Activity가 B Activity를 실행시켰을 때
    1) A가 onPause()됨
    2) B가 onCreate()~onResume()됨
    3) A가 onStop()~onSaveInstanceState()됨



singleTask가 다시실행되는 경우
Resume되어 있는 경우 : onPause() -> onNewIntent() -> onResume() 
Stop되어 있는 경우 : onNewIntent() -> onRestart() -> onStart() -> onResume()
아니라면 동일하게 onCreate()부터 시작





Fragment LifeCycle


onAttach() — Fragment가 생성된 후 Activity에 추가되는 시점에 호출된다. 
onCreate() — Fragment를 초기화 하는 시점에 호출된다.
onCreateView() — Fragment의 View를 Inflate하고 초기화해야 하는 시점에 호출된다.
onActivityCreated() — Activity의 onCreate() 가 완료되었을 때 호출된다. 
onStart() — Fragment가 화면에 표시될때 호출된다. Fragment의 뷰가 모두 만들어진 시점이다.
onResume() — Fragment가 화면에 표시되고 포커스를 갖고 있을 때 호출된다.
onPause() — Fragment가 포커스를 갖고 있지 않을 경우 호출된다.
onStop() — Fragment가 화면에서 보여지지 않을 때 호출된다.
onDestroyView() — Fragment 안에 생성되었던 View가 사라지는 시점에 호출된다. replace or backward로 removed되는 경우이다. (리소스들을 반환시켜야 한다면 여기서 반환하자)
onDestory() — Fragment가 완전히 종료되는 시점에 호출된다. 이 시점 이후 더 이상 Fragment를 사용할 수 없다.
onDetach() — Activity와 연결이 끊어질 때 호출된다.

* viewLifeCycleOwner에 대해 : 왜 Fragment에서는 LifeCycleOwner로 this가 아닌 viewLifeCycleOwner를 사용해야 하는가?
    Fragment에서는 View 관련 inflate 작업 등을 onCreateView()에서 하는데, Activity의 onCreate()와는 달리 이 메서드는 여러 번 호출될 수 있다.
    (Fragment Stack에서 backward로 갔다가 돌아올 때마다 호출됨)
    이 때마다 layout을 inflate 외에 DataBinding, ViewModel Observing등 처리가 되야 하는데, 이 때 ViewModel Observing 관련 주의사항은
    LifeCycleOwner를 this가 아니라 viewLifeCycleOwner로 지정해 주어야 한다는 것이다.
    this는 Fragment LifeCycleOwner로, onAttach() ~ onDetach()에 따라 장기간 살아있기 때문에 onCreateView()가 중복 호출될 때마다
    1개의 LifeCycleOwner에 동일 로직의 Observer가 등록 및 호출된다.
    viewLifeCycleOwner은 Fragment의 onCreateView()~onDestroyView() 동안만 살아있으므로, onCreateView()가 호출될 때마다 최신 LifeCycleOwner 객체인 것이다.
    따라서 중복으로 Observer가 등록되는 일을 방지할 수 있다.




Service LifeCycle
Service의 기본 LifeCycle은 아래와 같다.


Service는 startService() 또는 bindService()를 통해서 실행될 수 있다.
참고로 Service는 단 한 개의 객체만 Active상태로 존재할 수 있다.
즉, Service가 onCreate()됬으면 onDestroy()될 때까지는 아무리 startService(), bindService()를 호출하더라도 onCreate()는 다시 호출되지 않는다.
Service가 어떤 방법으로든 살아난 후에는 startService()를 호출하면 onStartCommand()가, bindService()를 호출하면 onBind()가 호출된다.
즉, Active상태에서는 서비스 실행 방법에 따라 호출되는 메서드가 다르다.


Activity Task & Back Stack
Reference : https://developer.android.com/guide/components/activities/tasks-and-back-stack?hl=ko 
1. 개요
 - 특정 작업을 수행할 때 사용자와 상호작용하는 액티비티들의 모음
 - 액티비티들은 실행된 순서대로 스택에 쌓인다. 이 스택을 Back Stack 이라고 한다.
 - Back Stack Process는 아래와 같다.
1) 현재 액티비티가 또 다른 액티비티를 실행할 때, 새로 실행된 액티비티는 스택의 Top에 Push 되고 Focus된다.
2) 이전의 액티비티는 스택에 유지되지만 실행이 멈춰진다.(onStop) 이 때, 시스템은 멈춰진 액티비티의 현재 UI 상태를 저장해 둔다.
3) 유저가 Back 버튼을 누르면 현재 액티비티는 스택의 Top 에서 Pop 된다.(onDestroy)
    그리고 직전의 액티비티가 멈출 때 저장한 UI 상태를 불러와서 다시 실행된다.(onResume)
* 스택에 있는 액티비티들은 절대 재배열 되지 않는다. 오직 스택에서 PUSH, POP 만 발생한다.
* 서로 다른 어플리케이션 간의 이동에도 Task를 이용해 사용자 경험(UX)를 유지시켜 준다.
* 최초 적재 액티비티는 Root Activity, 마지막으로 적재되는 액티비티는 Top Activity 라고 부른다.

 - 또한 Task의 Foreground/Background 상태는 아래와 같다.
1) Task의 Top Activity가 Foreground로 표시되면 해당 Task 또한 Foreground로 변경된다.
2) 나머지 화면에 나타나지 않는 Task들은 Background로 변경된다.


2. Task 관리
 - 위에서 설명했던 Task 의 기본 동작을 변경할 수 있다.
    1) Manifest에서 <activity>에 대한 attribute를 추가하여 속성 변경

Attribute Name Description Options
launchMode Activity를 Task로 실행하는 방식에 관한 지침을 지정

standard (기본 모드)
Activity가 실행될 때마다 새 Instance를 생성하며, 별도 플래그가 없으면 호출된 Task의

Top으로 들어간다.
(* 다중 Instance : 지원)

singleTop
실행시킨 Activity 의 인스턴스가 현재 Task 의 Top 에 이미 존재할 경우,
onNewIntent() 메서드를 통해 기존의 Activity 로 intent 를 라우팅한다.
만약 실행시킨 Activity의 인스턴스가 현재 Task에 존재하지만 Top이 아닌 경우에는
새 Instance를 생성한다.
(* 다중 Instance : 조건부)

singleTask
새로운 Task를 생성(단, taskAffinity가 다를 경우만)하고 새 Task에서 root Activity로

Instance를 생성한다.
만약 기존 Instance가 존재할 경우, onNewIntent() 메서드를 통해 기존의 Activity로
intent 를 라우팅한다.
참고로 singleTask에 의해서 만들어진 Task는 해당 Activity 외에도 다른 Activity를
쌓아 올릴 수 있지만, Task가 Background로 갔다 돌아오거나  singleTask Activity를 다시
호출하면 singleTask로 설정된 Activity 위에 쌓인 Activity를 모두 Destroy하고 singleTask Activity가 다시 Top이 된다.
(* 다중 Instance : 미지원)

singleInstance
SingleTask와 대부분 동일하지만, 새로 생성된 Task에는 singleInstance Activity 하나만
존재할 수 있다.
즉, 해당 Task Stack의 Size는 영원히 1이다.
(* 다중 Instance : 미지원)
taskAffinity Activity가 속하고자 하는 Task 명칭을 지정
Activity가 실행될 때, taskAffinity에 해당하는 Task가 존재하는 경우 해당 Task의 Top으로 포함된다.
단, singleInstance는 제외됨.
기본은 Package Name 또는 Application의 taskAffinity로 지정되며,
각 Activity별로 custom한 Task 명칭을 String으로 지정할 수 있다.
allowTaskReparenting 해당 Activity가 나중에 Task를 변경할 수 있는지 여부  기본은 false이며, allowTaskReparenting 속성을 true로 설정하면 시작된 task에서 동일한
affinity를 갖는 다른 task가 foreground로 올라올때 그 task로 activity가 이동될 수 있다.
clearTaskOnLaunch

홈 화면에서 시작 시 루트 액티비티를 제외하고 나머지를

제거할 지 여부

기본은 false이다.
Task의 Root Activity에 true로 설정되어 있다면 홈 화면에서 다시 시작할 때마다 루트 액티비티를 제외한 모든 액티비티를 Task에서 제거한다. 
alwaysRetainTaskState Task에 있는 Activity들을 오랜 시간 유지할 지 여부

기본은 false이다.
Task의 Root Activity에 true로 설정되어 있다면 오랜 시간 이후에도 Stack에 있는 모든

Activity를 유지한다.
(안드로이드 시스템 특성 상, 메모리 관리를 위해 오랜 시간동안 사용되지 않는 Task는 종료함)

finishOnTaskLaunch

사용자가 Task를 다시 시작할 때 해당 Activity의 Instance

를 종료할 지 여부

기본은 false이다.
true로 설정되어 있다면 Activity가 속한 Task가 Foreground로 변경될 때 해당 Activity의 Instance는 모두 종료된다.


    2) startActivity() 호출 시 Intent 의 Flag를 사용하여 속성 변경

Flag Description
FLAG_ACTIVITY_SINGLE_TOP  singleTop과 동일하다.
FLAG_ACTIVITY_NEW_TASK  singleTask 와 같다.
FLAG_ACTIVITY_CLEAR_TOP  백스택에 [A,B,C] 가 있고 C에서 B를 시작할 때 해당 플래그가 있으면 [A,B]가 된다.
보통 FLAG_ACTIVITY_SINGLE_TOP과 같이 쓰인다. 같이 쓰면 B를 시작할 때 onNewIntent() 메서드가 호출되고 같이 안 쓰면 onCreate()가 호출된다. 만약 백스택이 [A,B,A,B] 일 때 CLEAR_TOP 플래그로 A를 시작한다면 [A,B,A]가 된다.
FLAG_ACTIVITY_CLEAR_TASK  피호출자 액티비티가 시작하기 전에 관련된 스택이 모두 제거되고 피호출자 액티비티가 빈 태스크의 맨 아래에 놓인다.
CLEAR_TASK Flag는 NEW_TASK Flag와 반드시 함께 쓰여야 한다. (구글 공식 가이드)
예로 앱을 사용할 때 로그아웃하고 다른 아이디로 로그인하면 기존 태스크를 정리하고 새로운 메인 액티비티를 실행해야 한다.
이 때 두 플래그를 같이 사용한다.
추가로, 만약 현재 Task의 taskAffinity(root activity)와  실행할 Activity의 taskAffinity가 다르면
현재 Task는 건드리지 않고 실행할 Activity의 taskAffinity Task쪽으로 가서 Clear 후 새로 시작된다.
FLAG_ACTIVITY_REORDER_TO_FRONT 스택에 동일한 액티비티가 있다면 그 액티비티를 스택의 맨 위로 올린다.
단 FLAG_ACTIVITY_CLEAR_TOP과 같이 사용 못 한다. 

 

주의: 대부분의 앱은 활동 및 작업의 기본 동작을 중단해서는 안 됩니다.
개발자는 활동에서 기본 동작을 수정할 필요가 있다고 판단하면 신중하게 생각하고 활동 실행 중에 그리고 뒤로 버튼을 통해  
다른 활동 및 작업에서 이 활동으로 다시 이동할 때 활동의 사용성을 테스트해야 합니다.
사용자의 예상되는 동작과 충돌할 가능성이 있는 탐색 동작을 테스트해야 합니다.





View LifeCycle

 - Constructor() : 모든 뷰는 생성자에서 출발합니다. 생성자에서 초기화를 하고, default 값을 설정합니다.
                              뷰는 초기설정을 쉽게 세팅하기 위해서 AttributeSet이라는 인터페이스를 지원합니다.
                              먼저 attrs.xml파일을 만들고 이것을 부름으로써 뷰의 설정값을 쉽게 설정할 수 있습니다.
 - onAttachedToWindow() : 뷰가 윈도우에 Attach되었을 때 호출됩니다.
 - onMeasure() : 뷰의 크기(너비와 높이)를 결정하기 위해서 호출됩니다.
                             뷰의 크기를 측정 후에 setMeasuredDimension() 을 호출해 줘서 mMeasuredWidth / mMeasuredHeight 을 설정해야 합니다.
 - onLayout() : 뷰가 Child View를 가지고 있는 경우, 모든 자식에게 크기와 위치를 할당해 주기 위해 호출됩니다.
 - onDraw() : 뷰가 콘텐츠를 그려야 할 때 호출됩니다. Canvas가 인자로 전달되어 해당 Canvas에 그리면 됩니다.

스크롤이나 스와이프 등으로 화면 내용을 다시 그려야 하는 경우 invalidate()가 호출되면서 onDraw()가 다시 호출됩니다.
뷰 사이즈가 변경되면 requestLayout()이 호출되면서 다시 onDraw()가 호출됩니다.

추가로, User Input이 입력되면 관련 Callback이 호출됩니다.
 - onKeyDown(int, KeyEvent) : 물리 키 Down 이벤트 발생
 - onKeyUp(int, KeyEvent) : 물리 키 Up 이벤트 발생
 - onTrackballEvent(MotionEvent) : 트랙볼 이벤트 발생
 - onTouchEvent(android.view.MotionEvent) : 터치 이벤트 발생



 






추가 참조 자료 : https://lastyouth.tistory.com/24 : ANDROID DRAWING PROCESS