본문 바로가기
전공공부/모바일 프로그래밍

kotlin 공부 #3

by 시아나 2022. 3. 23.

안드로이드 4대 컴포넌트 :

  • 액티비티
  • 서비스
  • 브로드캐스트 리시버
  • 콘텐츠 프로바이더

액티비티 컴포넌트

- Intent : 컴포넌트를 실행하려고 시스템에 전달하는 메시지

- 엑스트라 데이터 : 인턴트에 담는 부가 정보

인텐트 필터 

  • 명시적 인텐트 : 클래스 타입 레퍼런스 정보를 활용한 인텐트
  • 암시적 인텐트 : 인텐트 필터 정보를 활용한 인텐트

- 인텐트 필터 하위에 설정 가능한 태그

  • <action> 컴포넌트의 기능을 나타내는 문자열
  • <category> 컴포넌트가 포함되는 범주를 나타내는 문자열
  • <data> 컴포넌트에 필요한 데이터 정보

액티비티 생명주기

- 생명주기 : 액티비티가 생성되어 소멸되기까지의 과정

[출처] https://developer.android.com/reference/android/app/Activity

- 액티비티 상태

  • 활성 : 액티비티 화면이 출력되고 있고 사용자가 이벤트를 발생시킬 수 있는 상태 
    액티비티가 포커스를 가지는 상태

  • 일시 정지 : 액티비티의 화면이 출력되고 있지만 사용자가 이벤트를 발생시킬 수 없는 상태
    onPause()함수까지 호출된 상태
    일반적으로 액티비티가 화면에 보이지만 포커스를 잃어 사용자 이벤트를 처리할 수 없는 상태
    ex) 화면 분할 모드

  • 비활성 : 액티비티의 화면이 출력되고 있지 않는 상태
    액티비티가 종료되지 않고 화면에만 보이지 않는 상태, onPause() -> onStop() 까지 호출됨.
    다시 실행시 onRestart() -> onStart() -> onResume() 호출(활성상태)
    ex) 인텐트로 다른 액티비티를 실행했거나 홈 버튼을 눌러 런처 화면으로 이동하는 경우

- Bundle 객체 : 액티비티를 종료할 때 저장했다가 복원해야 할 데이터가 있을때 사용할 수 있는 객체

액티비티 제어

- InputMethodManager 클래스 : 특정한 순간에 키보드를 들어올리거나 내려야 할 경우 사용가능

  • showSoftInput() : 소프트 키보드 나타남
  • hideSoftInputFromWindow() : 소프트 키보드 사라짐

=> 에디트 텍스트 같은 뷰에 포커스가 없는 상태에서 키보드가 나타나게 하려면 포커스를 강제로 지정{requestFocus()}한 후 showSoftInput() 함수를 호출해야함

태스크 관리

- 태스크(Task) 관리 : 액티비티를 어떻게 생성하고 관리하는지를 제어하는 일

- 액티비티 태스크 : 앱이 실행될 때 시스템에서 액티비티의 각종 정보를 저장하는 공간

- 태스크 제어 

  • 액티비티가 등록되는 매니페스트 파일의 <activity> 태그의 launchMode 속성으로 실행 모드를 설정
    => 항상 설정한 대로 생성되어 태스크에 등록
  • 인텐트의 flags 정보를 설정하여 제어
    => 이번 인텐트가 발생할 때에 한 번만 적용되어 태스크에 등록

액티비티 ANR 문제와 코루틴

- ANR 문제 : 액티비티가 응답하지 않는 오류 상황
     => 액티비티가 사용자 이벤트에 5초 이내에 반응하지 않으면 발생

val channel = Channel<Int>()
val backgroundScope = CoroutineScope(Dispatchers.Default + Job())
backgroundScope.launch{
	var sum = 0L
    var time = measureTimeMillis{
    	for(i in 1..2_000_000_000){
        	sum += i;
        }
	}
    Log.d("kkang","time : $time")
    channel.send(sum.toInt())
}

val mainScope = GlobalScope.launch(Dispatchers.Main){
	channel.consumeEach{
    	binding.resultView.text = "sum : $it"
	}
}

- 코루틴 : 비동기 경량 스레드
     => 장점 : 경량, 메모리 누수 적음, 취소 등 다양한 기능 제고 , 많은 제트팩 라이브러리에 적용되어 있음.

- 스코프 : 성격이 같은 코루틴을 묶는 개념, 성격이 같은 코루틴이 동작하는 공간 정도

- 디스패처 : 스코프에서 구동한 코루틴이 어디에서 동작해야 하는지를 나타냄

  • Dispatchers.Main : 액티비티의 메인 스레드에서 동작하는 코루틴을 만듬
  • Dispatcher.IO : 파일에 쓰기 또는 네트워크 작업 등에 최적화됨
  • Dispatcher.Default : CPU를 많이 사용하는 작업을 백그라운드에서 실행

브로드캐스트 리시버 컴포넌트

- 브로드캐스트 리시버 : 이벤트(부팅이 완료되는 것과 같은 시스템의 특정한상황) 모델로 실행되는 컴포넌트      

  • 액티비티나 서비스에서 생성하는 경우 : 항상 실행 / 암시적 인텐트로 실행 가능
  • 매니페스트에 등록해서 생성하는 경우 : 특정 상황에서 실행 / 암시적 인텐트로 실행 불가능

- 액티비티 인텐트는 시스템에 해당 인텐트로 실행될 액티비티가 없으면 오류, 실행될 액티비티가 여러개 있으면 사용자의 선택으로 하나만 실행

- 크로드캐스트 리시버는 시스템에 해당 인텐트로 실행될 리시버가 없으면 아무일 x, 시행될 리시버가 여러 개 있으면 모두 실행


서비스 컴포넌트

- 서비스 : 백그라운드 작업을 목적으로 하는 컴포넌트

  • startService() 함수로 실행
    해당 서비스를 인텐트에 담아서 매개변수로 전달
    => 백그라운드 작업은 필요하지만 액티비티와 데이터를 주고받을 일이 없는 등 서로 관련이 없는 서비스
val intnet = Intent(this, MyService::class.java)
startService(intent)

stopService(intent)

 

  • bindService() 함수로 실행
    ServiceConnection 인터페이스를 구현한 객체 준비 필요
    => 서비스와 액티비티 사이에 상호작용이 필요한 서비스
val connection: ServiceConnection = object : ServiceConnection{
	override fun onServiceConnected(name: ComponentName?, service: IBinder?) {}
    override fun onServiceDisconnected(name: ComponentName?) {}
}

val intent = Intent(this, MyService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)

unbindService(connection)

- 서비스 생명주기

[출처] https://developer.android.com/guide/components/services#Lifecycle

- IBindier : onBind() 함수의 반환 타입

//서비스 코드
class MyBinder : Binder(){
	fun funA(arg: Int){
    }
    fun funB(arg: Int): Int{
    	return arg*arg
    }
}

override fun onBind(intent: Intent): IBinder?{
	return MyBinder()
}

//액티비티 코드
val connection: ServiceConnection = object : ServiceConnection{
	override fun onServiceConnected(name: ComponetName?, service: IBinder?){
    	servideBinder = service as MyService.MyBinder
    }
    override fun onServiceDisconnected(name: ComponentName?){
    }
}

servideBinder.funA(10)

 

- 메신저 바인딩

//서비스 코드
class MyService : Service(){
	lateinit var messenger: Messenger
    internal class IncomingHandler(
    	context : Context,
        private val applicationContext: Context = context.applicationContext
    ) : Handler(Looper.getMainLooper()){
    	override fun handleMessage(msg: Message){
        	when(msg.what){
            	10 -> 
                	Toast.makeText(applicationContext, "${msg.obj}", Toast.LENGTH_SHORT).show()
                20 ->
                    Toast.makeText(applicationContext, "${msg.obj}", Toast.LENGTH_SHORT).show()
                else -> super.handleMessage(msg)
            }
        }
    }
 	override fun onBind(intent: Intent): IBinder?{
    	messenger = Messenger(IncomingHandler(this))
        return messenger.binder
    }
}

// 액티비티 코드
class MainActivity : AppCompatActivity(){
	lateinit var messenger: Messenger
    override fun onCreate(savedInstanceState: Bundle?){
    	supter.onCreate(savedInstanceState)
        ...
        val intent = Intent(this, MyService::class.java)
        bindService(intent, connection, Context.BIND_AUTO_CREATE)
    }
    val connection ServiceConnection = object : ServiceConnection{
    	override fun onServiceConnected(name: ComponentName?, service: IBinder?){
        	messenger = Messenger(service) 
        }
        override fun onServiceDisconnected(name : ComponentName?){
        }
    }
}

//서비스에 데이터 전달하고 싶을 때
val msg = Messenge()
msg.what = 10
msg.obj = "hello"
messenger.send(msg)

 

- AIDL 통신 기법 : 두 프로세스 사이에 데이터를 주고받는 프로세스 간 통신을 구현할 때 사용하는 기법으로, 서비스 컴포넌트의 bindService() 함수를 사용

백그라운드 제약

- 브로드캐스트 리시버의 백그라운드 제약
매니페스트에 등록한 리시버를 암시적 인텐트로 실행할 때에는 같은 앱의 리시버든 외부 앱의 리시버든 실행되지 않음

- 서비스의 백그라운드 제약
서비스는 앱이 백그라운드 상태일 때 인텐드를 전달하면 오류 발생

서비스가 정상적으로 실행되는 포그라운드 상황

  • 액티비티가 시작되든 일시 중지되든 상관없이 보이는 액티비티가 있을 때
  • 포그라운드 서비스가 있을 때
  • 앱의 서비스에 바인딩하거나 앱의 콘텐츠 프로바이더를 사용해 또 다른 포그라운드 앱이 연결되었을 때

이외에는 백그라운드 상황으로 간주함.
백그라운드 상황에도 정상 실행되는 경우

  • 우선순위가 높은 파이어베이스 클라우드 메시징(FCM) 처리
  • SMS/MMS 서비스와 같은 브로드캐스트 수신
  • 알림에서 PendingIntent 실행
  • VPN 앱이 포그라운드로 승격되기 전에 VpnService 시작

백그라운드 상황이더라도 startForground() 함수를 사용하여 앱을 포그라운드 상황으로 만들면 됨.

- 잡 스케줄러

  • 잡 서비스 : 백그라운드에서 처리할 작업을 구현한 서비스
  • 잡 인포 : 잡 서비스 정보와 실행될 조건을 지정
  • 잡 스케줄러 : 잡 인포를 시스템에 등록

콘텐츠 프로바이더 컴포넌트

- 콘텐츠 프로바이더 : 앱의 데이터를 다른 앱과 공유할 때 사용
     콘텐츠 프로바이더는 필요한 순간에 시스템에서 자동으로 생성해줌.

 

'전공공부 > 모바일 프로그래밍' 카테고리의 다른 글

책 "아키텍처를 알아야 앱 개발이 보인다" #2  (0) 2022.04.06
책 "아키텍처를 알아야 앱 개발이 보인다" #1  (0) 2022.04.06
kotlin 공부 #2  (0) 2022.03.22
looper  (0) 2021.08.31
23일차  (0) 2021.07.28