이것이 안드로이드다 with 코틀린(고돈호 지음) 으로 공부한 내용을 정리한 글입니다.
안드로이드에는 안드로이드 앱을 구성하는 4가지 컴포넌트가 존재하며, 그 중 액티비티는 사용자와 상호 작용하는 화면을 담당하는 컴포넌트입니다.
Context는 시스템을 사용하기 위한 정보(Property)와 도구(Method)가 담겨 있는 기본 클래스(Base Class)입니다. 대부분의 Context 는 컴포넌트 실행 시(Runtime) 생성됩니다.
액티비티는 이 Context 를 상속받아 구현되며, 코드상에서 baseContext
를 호출하는 것으로 안드로이드의 기본 기능을 사용할 수 있습니다.
Context 종류
- Application Context : 앱과 관련된 핵심 기능을 담고 있는 클래스로, 앱 전체에 하나의 인스턴스만 존재합니다.
- Base Context : 안드로이드 컴포넌트들의 Base Class 입니다. 각 컴포넌트들은 다른 Context 를 갖습니다.
인텐트는 컴포넌트를 실행하기 위해 시스템에 넘기는 정보입니다. 시스템이 자동으로 실행하는 컴포넌트를 제외한 컴포넌트들은 인텐트를 기반으로 실행됩니다.
액티비티 실행 과정
1. 실행할 액티비티 이름과 전달할 데이터를 담아서 인텐트를 생성
2. 생성한 인텐트를startActivity()
메서드에 담아서 호출 ➡ 인텐트가 액티비티 매니저에 전달됨
3. 액티비티 매니저는 인텐트를 분석해서 타깃 액티비티를 실행
4. 인텐트는 타깃 액티비티까지 전달됨
5. 타깃 액티비티에서는 전달받은 인텐트에 데이터가 있다면 이를 꺼내서 사용
인텐트 내부에는 번들(bundle) 이라는 데이터 저장 공간이 있는데, 이 번들에 데이터를 담아 액티비티끼리 주고받을 수 있습니다. 번들은 키와 값의 조합으로 데이터를 저장하며, 데이터를 꺼낼 때 키를 이용합니다.
// MainActivity
val intent = Intent(this, SubActivity::class.java)
intent.putExtra("key", "value")
// SubActivity
var text = intent.getStringExtra("key") // get<type>Extra(key, default)
전달된 인텐트를 얻기 위해 getIntent()
를 호출해야 했던 자바와 달리, 코틀린에서는 intent
가 액티비티 기본 프로퍼티이기 때문에 전달된 인텐트는 intent
로 바로 호출해서 사용할 수 있습니다.
startActivityForResult()
메서드를 사용하여 액티비티 B를 실행setResult()
메서드에 넣음onActivityResult()
메소드로 전달됨안드로이드는 액티비티의 상태 변화가 있을 때마다 생명 주기 메서드를 호출하여 상태 변화를 알려줍니다.
메서드 | 액티비티 상태 | 설명 |
---|---|---|
onCreate() | 만들어짐 | 액티비티가 생성됨 |
onStart() | 화면에 나타남 | 화면에 보이기 시작 |
onResume() | 실행 중 | 액티비티가 실행되고 있음 |
onPauese() | 화면이 가려짐 | 액티비티 화면의 일부가 다른 액티비티에 가려짐 |
onStop() | 화면이 없어짐 | 다른 액티비티에 의해 화면이 완전히 가려짐 |
onDestroy() | 종료돰 | 종료됨 |
onCreate()
메서드로 생성된 화면 구성요소를 메모리에 로드onStart()
와 onResume()
메서드에서 화면 구성요소를 나타내고 사용자와의 상호작용을 시작finish()
메서드로 액티비티를 종료하면 onPause()
와 onStop()
이 실행됨onDestroy()
가 호출되면서 액티비티가 메모리에서 제거됨onPause()
를 거쳐 onStop()
까지만 호출되고 종료되지는 않음onRestart()
와 onStart()
를 거쳐 onResume()
상태로 복귀함onPause()
까지만 호출onResume()
상태로 복귀함백스택은 액티비티 또는 화면 컴포넌트를 담는 안드로이드의 저장 공간입니다. 스택 구조를 갖고 있기 때문에 LIFO (Last In First Out) 로 동작합니다
안드로이드에서 프로세스는 앱의 실행 단위로, 앱당 하나의 프로세스가 생성됩니다. 태스크는 이 프로세스를 관리하는 작업 단위입니다. 한 앱에서 실행한 액티비티들(심지어 다른 앱의 액티비티일지라도)은 같은 태스크의 백스택에 쌓이게 됩니다.
컨테이너는 위젯이나 다른 레이아웃에 데이터를 동적으로 표현해줄 때 사용합니다. 컨테이너는 레이아웃과는 다르게 내부 요소의 위치를 결정할 수 있는 속성이 없으므로 레이아웃을 컨테이너 안에 삽입해서 사용합니다.
RecyclerView는 목록을 화면에 출력할 때 사용하는 대표적인 컨테이너 중 하나입니다. RecyclerView 처럼 목록을 위한 컨테이너들은 표시될 데이터와 레이아웃을 Adapter를 통해 연결합니다.
RecyclerView Adapter 는 개별 데이터에 대응하는 ViewHolder
클래스를 사용합니다.
class CustomAdapter : RecyclerView.Adapter<Holder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
// 한 화면에 그려지는 아이템 개수만큼 레이아웃 생성
}
override fun getItemCount(): Int {
// 목록에 보여줄 아이템의 개수
}
override fun onBindViewHolder(holder: Holder, position: Int) {
// 생성된 아이템 레이아웃에 값 입력 후 목록에 출력
}
}
ViewHolder
는 아이템 레이아웃을 포함하고 있는데, 화면에 보여지는 개수만큼만 홀더를 생성하고 스크롤 될 경우 가려지게 되는 홀더를 재사용하여 데이터만 바꿔주기 때문에 필요없는 레이아웃을 생성함으로써 자원이 낭비되는 것을 방지합니다.
class Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
// 레이아웃에 데이터를 세팅하는 메서드 구현
}
ViewHolder
클래스의 생성자는 다음에 만들 어댑터의 아이템 레이아웃이 필요한데, 이는 ViewHolder
자체에서 만들지 않고 RecyclerViewAdapter
에서 레이아웃을 View
객체로 변환시켜 ViewHolder
로 전달합니다.
뷰홀더가 생성되는 시점에 클릭 리스너를 추가하여 목록 클릭 이벤트를 처리합니다.
class Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
init {
itemView.setOnClickListener {
// 클릭 이벤트 처리
}
}
}