반응형
Android Activity 생명주기와 실전 구현 방법 (기본)
Android 개발을 시작하면 반드시 알아야 하는 핵심 개념 중 하나가 바로 'Activity'입니다. Activity는 사용자와 직접 상호작용하는 화면을 담당하는 Android 앱 개발의 근간이 되는 요소입니다. 이 글에서는 초보 개발자도 쉽게 이해할 수 있도록 Activity의 기본 개념, 생명주기, 실전 구현 방법까지 상세히 알아보겠습니다. Android 공식 문서에서는 Activity를 "앱과 사용자가 상호작용할 수 있는 진입점이며, 앱이 UI를 그리는 창을 제공"한다고 정의합니다.
목차
1. Activity의 개념과 기본 구현
2. Activity 생명주기 완벽 이해
3. Activity 간 전환과 데이터 전달
4. Launch Mode와 상태 저장
5. 최신 Android 아키텍처 적용
#1. Activity의 개념과 기본 구현
Activity는 Android 앱에서 사용자와 상호작용하기 위한 단일 화면을 의미합니다. 앱은 보통 여러 개의 Activity로 구성되며, 각 Activity는 서로 다른 기능과 화면을 담당합니다.
1) Activity의 핵심 특징
① android.app.Activity 클래스를 상속받아 구현합니다
② 최근에는 주로 androidx.appcompat.app.AppCompatActivity를 사용하여 하위 버전 호환성을 유지합니다
③ 각 Activity는 고유한 화면 레이아웃과 생명주기를 가집니다
④ 사용자 인터페이스와 비즈니스 로직을 함께 관리합니다
. . . . .
2) 기본 Activity 만들기
(1) Kotlin으로 작성한 기본 Activity
// Kotlin으로 작성한 기본 Activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// UI 초기화 작업
val button = findViewById<Button>(R.id.button_start)
button.setOnClickListener {
// 버튼 클릭 처리
}
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// UI 초기화 작업
val button = findViewById<Button>(R.id.button_start)
button.setOnClickListener {
// 버튼 클릭 처리
}
}
}
(2) AndroidManifest.xml에 등록하기
모든 Activity는 Android 시스템에 등록되어야 합니다. 이 작업은 AndroidManifest.xml 파일에서 이루어집니다:
<!-- AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<!-- 메인 Activity 선언 -->
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<!-- 메인 Activity 선언 -->
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
android:exported="true"는 다른 앱에서 이 Activity를 시작할 수 있음을 의미하고, intent-filter의 MAIN 액션과 LAUNCHER 카테고리는 앱 런처에서 이 Activity를 시작 화면으로 표시합니다.
#2. Activity 생명주기 완벽 이해
Activity의 가장 중요한 특징 중 하나는 '생명주기(Lifecycle)'입니다. Activity는 생성되고, 사용자에게 보여지고, 다시 숨겨지며, 종료되기까지 여러 상태 변화를 겪게 됩니다.
1) Activity 생명주기 7가지 메서드
| 메서드 | 설명 | 주요 작업 |
|---|---|---|
| onCreate() | Activity가 처음 생성될 때 호출 | 레이아웃 설정, 뷰 초기화, 데이터 바인딩 |
| onStart() | 사용자에게 보여지기 직전 호출 | UI 업데이트 준비, 애니메이션 준비 |
| onResume() | 사용자와 상호작용 가능 상태 | 실시간 데이터 업데이트, 카메라/센서 시작 |
| onPause() | 부분적으로 보이지 않을 때 호출 | 애니메이션 일시중지, 중요 데이터 저장 |
| onStop() | 완전히 가려질 때 호출 | 무거운 리소스 해제, DB 연결 해제 |
| onRestart() | 중지 후 다시 시작될 때 호출 | 일시중지된 작업 재개 준비 |
| onDestroy() | 완전히 종료되기 전 호출 | 모든 리소스 해제, 메모리 누수 방지 |
. . . . .
2) 생명주기 메서드 실전 코드
(1) onCreate() - UI 초기화
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// UI 초기화, 뷰 바인딩, 데이터 준비
val button = findViewById<Button>(R.id.button_start)
button.setOnClickListener {
// 버튼 클릭 처리
}
}
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// UI 초기화, 뷰 바인딩, 데이터 준비
val button = findViewById<Button>(R.id.button_start)
button.setOnClickListener {
// 버튼 클릭 처리
}
}
(2) onResume()과 onPause() - 리소스 관리
override fun onResume() {
super.onResume()
// 실시간 업데이트, 애니메이션 시작
startLocationUpdates()
resumeAnimations()
}
override fun onPause() {
super.onPause()
// 리소스 집약적 작업 일시 중지
stopLocationUpdates()
pauseAnimations()
saveImportantData()
}
super.onResume()
// 실시간 업데이트, 애니메이션 시작
startLocationUpdates()
resumeAnimations()
}
override fun onPause() {
super.onPause()
// 리소스 집약적 작업 일시 중지
stopLocationUpdates()
pauseAnimations()
saveImportantData()
}
. . . . .
3) 주요 생명주기 이벤트 흐름
① Activity 시작 - onCreate() → onStart() → onResume()
② Activity 일시 중지 - onPause()
③ Activity 중지 - onPause() → onStop()
④ Activity 재시작 - onRestart() → onStart() → onResume()
⑤ Activity 종료 - onPause() → onStop() → onDestroy()
#3. Activity 간 전환과 데이터 전달
1) Intent로 새 Activity 시작하기
Android에서는 Intent를 사용하여 Activity 간 전환을 수행합니다:
// Kotlin에서 새 Activity 시작하기
val button = findViewById<Button>(R.id.button_start)
button.setOnClickListener {
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)
}
val button = findViewById<Button>(R.id.button_start)
button.setOnClickListener {
val intent = Intent(this, SecondActivity::class.java)
startActivity(intent)
}
. . . . .
2) Intent로 데이터 전달하기
(1) 데이터 전송하는 Activity
// Kotlin으로 데이터 전달하기
val intent = Intent(this, SecondActivity::class.java).apply {
putExtra("user_name", "John Doe")
putExtra("user_age", 25)
putExtra("is_premium", true)
}
startActivity(intent)
val intent = Intent(this, SecondActivity::class.java).apply {
putExtra("user_name", "John Doe")
putExtra("user_age", 25)
putExtra("is_premium", true)
}
startActivity(intent)
(2) 데이터 수신하는 Activity
// 전달받은 데이터 읽기
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
val userName = intent.getStringExtra("user_name") ?: "Unknown"
val userAge = intent.getIntExtra("user_age", 0)
val isPremium = intent.getBooleanExtra("is_premium", false)
// 데이터 사용하기
val textView = findViewById<TextView>(R.id.text_view)
textView.text = "Name: $userName, Age: $userAge"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
val userName = intent.getStringExtra("user_name") ?: "Unknown"
val userAge = intent.getIntExtra("user_age", 0)
val isPremium = intent.getBooleanExtra("is_premium", false)
// 데이터 사용하기
val textView = findViewById<TextView>(R.id.text_view)
textView.text = "Name: $userName, Age: $userAge"
}
. . . . .
3) ActivityResultLauncher로 결과 받아오기
최신 Android에서는 ActivityResultLauncher를 사용하여 결과를 받아옵니다:
// 최신 방식 (ActivityResultLauncher 사용)
private val startForResult = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data = result.data
val returnedText = data?.getStringExtra("result_text") ?: ""
Toast.makeText(this, "Returned: $returnedText", Toast.LENGTH_SHORT).show()
}
}
// 버튼 클릭 시 Activity 시작
binding.buttonStartForResult.setOnClickListener {
val intent = Intent(this, InputActivity::class.java)
startForResult.launch(intent)
}
private val startForResult = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data = result.data
val returnedText = data?.getStringExtra("result_text") ?: ""
Toast.makeText(this, "Returned: $returnedText", Toast.LENGTH_SHORT).show()
}
}
// 버튼 클릭 시 Activity 시작
binding.buttonStartForResult.setOnClickListener {
val intent = Intent(this, InputActivity::class.java)
startForResult.launch(intent)
}
#4. Launch Mode와 상태 저장
1) Activity의 4가지 실행 모드
| Launch Mode | 설명 | 사용 예 |
|---|---|---|
| standard | 기본 모드, 항상 새 인스턴스 생성 | 일반적인 화면 전환 |
| singleTop | 최상단에 동일 Activity가 있으면 재사용 | 알림에서 Activity 시작 |
| singleTask | 태스크에 인스턴스 하나만 존재 | 홈 화면, 주요 진입점 |
| singleInstance | 독자적인 태스크에서 단독 실행 | 전화 앱 호출 화면 |
. . . . .
2) Activity 상태 저장 및 복원
화면 회전 등으로 Activity가 재생성될 때 상태를 유지하기 위한 방법:
// 상태 저장하기
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("user_input", binding.editTextInput.text.toString())
outState.putInt("counter", counter)
}
// 상태 복원하기
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (savedInstanceState != null) {
val userInput = savedInstanceState.getString("user_input", "")
counter = savedInstanceState.getInt("counter", 0)
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("user_input", binding.editTextInput.text.toString())
outState.putInt("counter", counter)
}
// 상태 복원하기
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (savedInstanceState != null) {
val userInput = savedInstanceState.getString("user_input", "")
counter = savedInstanceState.getInt("counter", 0)
}
}
#5. 최신 Android 아키텍처 적용
1) ViewModel과 Activity
ViewModel을 사용하여 UI 데이터를 관리하고 화면 회전 시에도 데이터를 유지할 수 있습니다:
// ViewModel 정의
class MainViewModel : ViewModel() {
private val _counter = MutableLiveData<Int>(0)
val counter: LiveData<Int> = _counter
fun incrementCounter() {
_counter.value = (_counter.value ?: 0) + 1
}
}
// Activity에서 ViewModel 사용
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
// LiveData 관찰
viewModel.counter.observe(this) { count ->
binding.textViewCounter.text = "Counter: $count"
}
}
}
class MainViewModel : ViewModel() {
private val _counter = MutableLiveData<Int>(0)
val counter: LiveData<Int> = _counter
fun incrementCounter() {
_counter.value = (_counter.value ?: 0) + 1
}
}
// Activity에서 ViewModel 사용
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
// LiveData 관찰
viewModel.counter.observe(this) { count ->
binding.textViewCounter.text = "Counter: $count"
}
}
}
. . . . .
2) 권한 처리하기
Android 6.0(API 23) 이상부터는 위험 권한을 실행 시간에 요청해야 합니다:
// 권한 확인 및 요청
private fun checkAndRequestPermission() {
if (ContextCompat.checkSelfPermission(
this, Manifest.permission.CAMERA
) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
CAMERA_PERMISSION_REQUEST_CODE
)
} else {
startCamera()
}
}
private fun checkAndRequestPermission() {
if (ContextCompat.checkSelfPermission(
this, Manifest.permission.CAMERA
) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
CAMERA_PERMISSION_REQUEST_CODE
)
} else {
startCamera()
}
}
마무리
Activity는 Android 앱 개발의 핵심 구성 요소로서, 사용자 인터페이스와 상호작용을 담당합니다. 이 글에서는 Activity의 기본 개념부터 생명주기, 데이터 전달, 그리고 최신 아키텍처 적용까지 살펴보았습니다.
핵심 요약
① Activity는 사용자와 상호작용하는 단일 화면을 담당합니다
② 생명주기 7가지 메서드를 이해하고 적절히 활용해야 합니다
③ Intent를 사용하여 Activity 간 전환과 데이터 전달을 수행합니다
④ Launch Mode를 활용하여 Activity 인스턴스 관리를 최적화합니다
⑤ ViewModel과 LiveData를 사용하여 최신 아키텍처를 적용합니다
Activity의 생명주기를 제대로 이해하고 관리하는 것은 안정적이고 효율적인 Android 앱을 만드는 기초입니다. 처음에는 복잡해 보일 수 있지만, 실제 프로젝트에서 반복적으로 사용하다 보면 자연스럽게 익숙해질 것입니다. 이 글이 Android 개발의 기본을 다지는 데 도움이 되었기를 바랍니다!
긴 글 읽어주셔서 감사합니다.
끝.
끝.
반응형
'Development > Android' 카테고리의 다른 글
| [Android] Android GC_CONCURRENT FREED 에러 해결 방법과 메모리 최적화 (0) | 2020.04.08 |
|---|---|
| [Android] Android Context 완벽 이해 - 종류별 사용법과 메모리 누수 해결 (0) | 2020.04.08 |
| [Android ] Android Intent Flag 완벽 가이드 - 화면 전환 제어 방법 (0) | 2020.04.08 |
| [Android] Android ArrayList 객체를 Intent로 전달하는 3가지 방법 (3) | 2020.04.08 |
| [Android] Android Activity 오류 해결 및 성능 최적화 방법 (0) | 2020.04.08 |