LifeCycle 실행 추적해보면서 이해하기 - Activity 실습
우선 "애플리케이션"이 LifeCycle 메소드를 이용해서
안드로이드 운영체제에 대한 예외상황을 어떻게 처리하는지 이해해보자.
그렇기에, LifeCycle 메소드가 실행되는 과정을 추적하기 위해 아래와 같은 코드를 구성했다.
LifeCycle 메소드를 실행하면 Toast 메소드로 AVD에 실행된 LifeCycle 메소드 명을 출력되도록 설정해줬다.
그래서, AVD를 이용해 애플리케이션의 안드로이드 운영체제에 대한 예외상황들을 작동해보며,
LifeCycle 메소드가 어떻게 실행되는지를 살펴보면 되겠다.
# 테스팅 과정은 아래와 같다.
{Testing 과정}
앱을 실행하면, Toast 메시지가 어떠한 것들이 출력되는지 확인
그리고, 홈버튼을 눌러 홈으로 이동할 때 Toast 메시지가 어떠한 것들이 출력되는 지 확인
다시 앱을 클릭해 실행했을 때 Toast 메시지가 어떠한 것들이 출력되는 지 확인
package com.example.umc_week4
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
class MainActivity : AppCompatActivity() {
// onCreate() 메소드 구현
override fun onCreate (savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show()
}
// LifeCycle 메소드들이 실행되는 구조를 시각화하기 위한 코드임.
/*
Toast() 메소드를 이용해서 AVD에서 출력문구를 띄움.
{Testing 과정}
앱을 실행하면, Toast 메시지가 어떠한 것들이 출력되는지 확인
그리고, 홈버튼을 눌러 홈으로 이동할 때 Toast 메시지가 어떠한 것들이 출력되는 지 확인
다시 앱을 클릭해 실행했을 때 Toast 메시지가 어떠한 것들이 출력되는 지 확인
*/
override fun onStart(){
super.onStart()
Toast.makeText(this, "onStart", Toast.LENGTH_SHORT).show()
}
override fun onResume(){
super.onResume()
Toast.makeText(this, "onResume", Toast.LENGTH_SHORT).show()
}
override fun onPause(){
super.onPause()
Toast.makeText(this, "onPause", Toast.LENGTH_SHORT).show()
}
override fun onStop(){
super.onStop()
Toast.makeText(this, "onStop", Toast.LENGTH_SHORT).show()
}
override fun onRestart(){
super.onRestart()
Toast.makeText(this, "onRestart", Toast.LENGTH_SHORT).show()
}
override fun onDestroy(){
super.onDestroy()
Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show()
}
}
LifeCycle 작동 결과
# 앱 첫 실행 시
onCreate() -> onStart() -> onResume()
# 홈 버튼을 클릭 시
onPause()-> onStop()
# 다시 앱 실행
onRestart() -> onStart() -> onResume()
# 앱 종료 시 ( 나가기 버튼을 클릭 | 홈 버튼 옆에 있는 버튼 )
onPause() -> onStop() -> onDestory()
UMC 안드로이드 4주차 Standard Mission
LifeCycle를 활용하여 메모장 앱 만들기
기획
- 메모화면 (Edit Text와 다음화면으로 넘어가는 Button)
- 메모 확인 화면
# LifeCycle 기능
- onCreate() - {메모화면, 메모 확인 화면}
- layout을 Activity로 화면 구성
- layout을 Activity로 화면 구성
- onStop() - {메모화면}
- Edit Text 값을 전역변수에 기억
- Edit Text 값 비우기
- onRestart() - {메모화면}
- Dialog를 사용해 이어서 작성할 지 유무 묻기
- 예 | Edit Text = 전역변수
- 아니요 | Edit Text 빈 값으로 출력 & 전역변수 빈 값으로 지정
- Dialog를 사용해 이어서 작성할 지 유무 묻기
메모장 앱 구현 - LifeCycle 적용 { onCreate(), onPause(), onRestart() }
메모장 화면에 대한 xml 구현
우선 메모장 앱을 구현하고자, 메모장 화면을 구성했다.
메모장 화면의 구성은 아래와 같다.
- LinearLayout
- TextView
- EditText
- Button
( actvitiy_main.xml )
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="동욱이의 메모장"
android:textSize="35dp"/>
<EditText
android:id="@+id/edt_main"
android:layout_width="match_parent"
android:layout_height="388dp"></EditText>
<Button
android:id="@+id/btn_main"
android:layout_width="match_parent"
android:layout_height="67dp"
android:text="메모 저장"></Button>
</LinearLayout>
구현된 메모장 화면
메모 확인 화면에 대한 xml 구현
버튼을 눌렀을 때 등장하는 다음 화면으로, 메모 확인 화면을 구성했다.
메모 확인 화면의 구성은 아래와 같다.
- constraintLayout
- TextView
( actvitiy_second.xml )
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/txt_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="받아온 데이터 보여주기"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</TextView>
</androidx.constraintlayout.widget.ConstraintLayout>
구현된 메모 확인 화면
메모장 화면에 대한 Activity 구현
xml에 대한 viewBinding 클래스를 이용해 메모장 화면을 구현했다.
(viewBinding을 이용한 화면 구성은 UMC 3주차에서 다뤘으니, 참고하길 바란다.)
메모장 화면에는 Button이 있기에,
Button의 클릭이 들어오면 메모 확인 화면으로 Intent를 이용한
Activity 전환 (화면전환)을 수행하도록 구현했다.
그리고, Intent에 EditText 값을 담아서 넘겨주었다.
# LifeCycle 구현
onStop() 메소드를 구현했고,
해당 메소드에선 Activity 방출 전환이 발생했을 때나,
외부 요인으로 앱 작동이 멈추었을 때 구현된다.
onStop() 메소드는 전역변수에 값을 기억하고,
Edit Text 비우는 행위를 구현했다.
onRestart() 메소드를 구현했다.
해당 메소드에선 Activity 인출 전환이 발생했을 때나,
다시 앱을 작동할 때 구현된다.
onRestart() 메소드는 Dialog를 뛰워서,
클라이언트의 요청에 따른 다른 작동을 구현했다.
Yes : Edit Text 이전 데이터 불러오기
No: Edit Text 비우기
( MainActivity )
package com.example.umc_week4
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.Editable
import android.widget.EditText
import android.widget.Toast
import com.example.umc_week4.databinding.ActivityMainBinding
// Diolog 구현하기 위한 모듈
import android.content.DialogInterface
import androidx.appcompat.app.AlertDialog
class MainActivity : AppCompatActivity() {
/*
TO DO 1.
onStop() 메소드 호출 시 Edit Text 값을 기억할 필드변수 선언
*/
private lateinit var edit_data: String
// ActivityMainBinding 클래스에 대한 타입으로 viewBinding 변수 선언
private lateinit var viewBinding: ActivityMainBinding
// onCreate() 메소드 구현 | ViewBinding으로 Layout 객체로 생성 & Layout 객체받아서 화면 출력
override fun onCreate (savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// viewBinding에 ActivityMainBinding 객체 생성해줌.
viewBinding = ActivityMainBinding.inflate(layoutInflater)
// view에 viewBinding의 모든 객체를 지정함.
val view = viewBinding.root
// MainActivity에서 viewBinding 객체를 모두 보여줌.
setContentView(view)
viewBinding.btnMain.setOnClickListener {
// 버튼이 클릭되면, SecondActivity로 전환
/*
명시적 Intent로 Activity 전환
*/
var intent = Intent(this, SecondActivity::class.java)
// intent에 전달 데이터 값을 담어서 전달가능
intent.putExtra("data", viewBinding.edtMain.text.toString())
// startActivity() 메소드로 intent 실행시켜 Activity 전환
startActivity(intent)
}
}
override fun onStop() {
super.onStop()
// Edit Text 값은 전역변수에 기억
edit_data = viewBinding.edtMain.text.toString()
// Edit Text 값 비우기
/*
Edit Text의 타입인 Editable 맞추느라 고생했다.
null도 안되고, 오직 Editable 값만 받아줌.
*/
viewBinding.edtMain.text = Editable.Factory.getInstance().newEditable("")
}
override fun onRestart() {
super.onRestart()
// Diolog를 사용해 메모장 이어서 작성할 건지 유무 묻고 나눠서 실행
// 홈버튼 눌러서 나갔다가, 다시 앱에 접속했을 때 실행됨
// 다이얼로그를 생성하기 위해 Builder 클래스 생성자를 이용해 줍니다.
val builder = AlertDialog.Builder(this)
builder.setTitle("메모장 관리자")
.setMessage("메모장에 작성 중인 글을 이어서 작성할까요?")
.setPositiveButton("예",
DialogInterface.OnClickListener { dialog, id ->
// Editable 형태로 바꿔서 대입 || Edit Text는 Editable 타입 아닌 그외의 것들은 안받아줌.
viewBinding.edtMain.text = Editable.Factory.getInstance().newEditable(edit_data)
})
.setNegativeButton("아니요",
DialogInterface.OnClickListener { dialog, id ->
edit_data = ""
})
// 다이얼로그를 띄워주기
builder.show()
}
}
메모 확인 화면에 대한 Activity 구현
activity_second.xml 에 대한 Binding 클래스를 받아서
메모 확인 화면으로 구성한다.
(이 부분에 대해선 UMC 3주차에서 자세히 다뤘으니 참고바란다.)
intent로 전달받을 때
이전 Activity에서 putExtra() 메소드를 통해 Edit Text 입력값을 전달된 걸
받아서 Text View의 Text로 구성한다.
( SecondActivity )
package com.example.umc_week4
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.umc_week4.databinding.ActivitySecondBinding
class SecondActivity: AppCompatActivity() {
// viewBinding 클래스 받아오기
private lateinit var viewBinding: ActivitySecondBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivitySecondBinding.inflate(layoutInflater)
val view = viewBinding.root
setContentView(view)
// intent로 전환된 SecondActivity에서 전달된 데이터를 받아 Second XML text에 보여줌.
viewBinding.txtSecond.text = intent.getStringExtra("data")
}
}
구현 끝 & 구현영상
실습하면서 겪었던 에러 모음 | 트러블 슈팅
실습하면서 어려웠던 것들 모음 | 트러블 슈팅
트러블 슈팅이란, 시스템이나 장치 등에서 발생한 장애를 각종 수법을 활용하여 원인을 찾아내는 과정이자 행위이다.
즉, 시스템에서 발생하는 복잡한 문제들을 종합적으로 진단해 처리하는 수법이다.
트러블 슈팅의 과정
1. 에러 정의
2. 에러 원인 추론
3. 에러 조치
4. 결과 관찰
5. {만약 문제가 다시 발생한다면 3번으로 다시}
이런 순서로 3-4번은 해결 될 때까지 루프를 돈다.
포스팅하는 트러블 슈팅은
에러를 해결 완료하고 올리는 사항들이니, 트러블 슈팅을 커스텀마이징해서 기록하겠다.
1. 에러 정의
2. 에러 원인
3. 에러 해결 (원인에 대한 해결책 & 해결 과정)
- 자동으로 xml에 대한 viewBinding 클래스가 생성되지 않는 에러 { 에러 }
{에러 정의}
xml 파일로 Layout을 생성해주면,
안드로이드에서 자동으로 xml의 Layout에 대한 viewBinding 클래스를 만들어준다.
(Activity에서 해당 클래스를 받아서 화면에 보여주기 위함.)
그래서, MainActivity에서 ActivityMainBinding 클래스를 가져와
viewBinding 객체?로 지정해줬다.
그치만... ActivityMainBinding 클래스를 불러올 수 없다는 에러가 계속 생겼다.
{에러 원인}
ActivityMainBinding 클래스가 생성되지 않아
ActivityMainBinding 클래스를 불러올 수 없다는 에러가 발생한 것이다.
즉, xml에 대한 Binding 클래스 파일이 생성되지 않아
Binding 클래스를 불러올 수 없다는 에러이다.
{에러 해결}
에러는 아래의 블로그를 참고해서 에러를 해결할 수 있었다.
# 에러 해결의 리소스
에러의 원인이었던, Xml에 대한 Binding 클래스 파일이 생성되지 않았던 이유는
안드로이드 프로젝트에서 원래는 자동으로 xml에 대해 viewBinding 클래스를
생성해주는데,
"자동으로" 생성해주는 설정이 사라져서
자동으로 viewBinding 클래스를 생성해주지 않고 있었던 것이다.
그렇기에, 안드로이드 프로젝트인 "umc_week4"에 대해 "자동으로" viewBinding 클래스를 생성해주는 설정을 추가함으로써,
xml에 대한 viewBinding 클래스가 생성되지 않았던 에러를 해결했다.
# 에러의 해결과정
1. build.gradle(Module) 파일에서
android 블록안에 아무곳에나 아래와 같은 코드를 추가한다.
buildFeatures{
viewBinding = true
}
2. 상단의 Sync Project with Gradle Files를 클릭한다. (아마 수정한 gradle 파일 구성에 대해 재실행같은 것일거다.)
# 해결완료 & 정리
다음과 같은 두 과정을 수행하면, 이제,
자동으로 xml 파일에 대한 viewBinding 클래스가 생성될 것이다.
- Dialog 화면에 띄우는 설정 | 코틀린 { 어려웠던 점 }
Dialog 설정해주는데 많이 애를 먹었다 ㅎㅎㅋㅋ
# Dialog 활용 설명
클라이언트가 외부 요인으로 인해 앱을 종료되어 다시 액티비티에 접근하거나, 다른 액티비티에서 넘어올 때
현재 Activity에서 구현된 Edit Text 데이터를 이어서 작성할 건지 처음부터 작성할 건지에 대한 의사를 묻고자
Dialog를 활용해 구현을 완료했다.
# Dialog 사용하면서 어려웠던 점
Dialog와 관련한 메소드들이 인식하지 못하는 에러를 해결하기가 어려웠었다.
(코드를 블로그에 있던 것들을 복사해서 수정했기에 처음에는 제대로 작동이 안되었다.)
# 해결
해결법은 단순했다.
아래의 코드를 액티비티 파일에 추가하여
Dialog 모듈을 불러오면 되었다 ㅋㅋ
// Diolog 구현하기 위한 모듈
import android.content.DialogInterface
import androidx.appcompat.app.AlertDialog
결국, 이번에 겪었던 Dialog 사용의 어려움은 처음쓰는 메소드이기에 미숙해서 그런 듯하다.
다음부턴, 처음쓰는 메소드를 사용할 때는 모듈을 불러서 쓰는 건지, 내장하고 있는 메소드인지를 분명히 한 후 개발을 하는 습관을 들이도록 하겠다.
(프로젝트에서 설계가 가장 중요하듯, 개발에 있어 코드 구성도 중요하다.)
# Dialog를 화면에 띄우도록 구현 완료한 코드
아래의 코드는 onRestart() 메소드 내에 구현된 Dialog를 띄우는 설정과 관련한 코드이다.
// 다이얼로그를 생성하기 위해 Builder 클래스 생성자를 이용해 줍니다.
val builder = AlertDialog.Builder(this)
builder.setTitle("메모장 관리자")
.setMessage("메모장에 작성 중인 글을 이어서 작성할까요?")
.setPositiveButton("예",
DialogInterface.OnClickListener { dialog, id ->
// Editable 형태로 바꿔서 대입 || Edit Text는 Editable 타입 아닌 그외의 것들은 안받아줌.
viewBinding.edtMain.text = Editable.Factory.getInstance().newEditable(edit_data)
})
.setNegativeButton("아니요",
DialogInterface.OnClickListener { dialog, id ->
edit_data = ""
})
// 다이얼로그를 띄워주기22
builder.show()
# 구글링하며 느꼈던 사항
생각보다 안드로이드 개발을 Java로 개발하는 분들이 많다. 그래서, 코드를 참조할 때 Java 언어로 구현된 사항을 참고하면
안드로이드 스튜디오 Activity에서 작동하지 못한다 ㅠ
그렇기에, 안드로이드 개발을 하면서 찾은 참고자료들을 볼 때는 우선 Kotlin으로 작성된 것인지 확인하고 참고하는 것이 좋을 것 같다.
- Edit Text 공백으로 채우기 {에러 & 어려웠던 점}
{에러 정의}
Edit Text의 값을 공백으로 채우고자 아래와 같은 코드를 작성했다.
viewBinding.edtMain.text = ""
"" 이는 문자열로, 공백으로 Edit Text 값을 채운다. 라는 의도로 작성했지만, AVD 실행을 해보면
logcat에서 Edit Text의 Text 값으로는 String을 넣을 수 없다고 한다 ㅎㅎ..
그래서 구글링을 통해
Edit Text를 공백으로 만들고자 관련 메소드들을 찾아서 코드를 아래와 같이 작성했다.
viewBinding.edtMain.text.setText(null)
setText() 메소드를 사용해서 null 값으로 바꿔주는 메소드를 호출했지만, setText() 메소드를 인식하지 못하는 에러가 발생했다.
{에러 원인}
Edit Text의 Text 값의 데이터 타입은 Editable이다.
그치만, 위에서 작성한 건 ""으로 String 이다. 그래서 Type Mismatch 에러가 발생했다.
{에러 해결}
Edit Text의 Text 전달 값은 Editable 타입으로만 전달받는다. 그렇기에 이에대한 타입을 일치시켜
Editable 타입으로 Edit Text의 Text 값을 지정하여 에러를 해결할 수 있었다.
# 에러의 해결 과정
아래와 같은 코드를 구현해서 Edit Text 값에 대한 타입 (Editable)으로 Edit Text의 Text 값을 지정해줬다.
viewBinding.edtMain.text = Editable.Factory.getInstance().newEditable("")
# 해결완료 & 고찰
이번 에러를 해결하면서 애를 많이 먹었다. 쉬울 줄 알았는데, 예상치 못한 곳에서 에러가 발생해서 당황하긴 했다.
그치만, Edit Text의 Text 값을 변경하는 방법에 대해 알아보며
여러 가지 방법들이 있었고, 그 방법들을 모두 사용해봄으로써 결국 에러에 대한 해답을 찾아낼 수 있었다.
그리고, 여러 가지 방법들이 있더라도 어떤게 답이 아니고, 단지 나의 개발환경에 적합한 에러를 골라서 사용하면
에러는 자연스럽게 해결되어질 것이다. 라는 걸 깨달았다.
그래서, 앞으로 에러를 만날 때의 자세는 해답은 어딘가에 있으니, 될 때까지 해보자라는 마음가짐을 더 굳게 다지게 되는 계기가 되었다.
마치며...
# 실습하면서 느낀점
이번 UMC 4주차 실습은 개인 역량이 많이 필요로 하는 실습이었던 것 같다.
그렇기에, 시간이 비교적 많이 걸리고, 실습 과제가 생각보다 추상적이었다.
그치만, 실습 과제에 대한 기획을 차근차근히 설계하고 개발을 진행하니 생각보다 쉽게 구현할 수 있었다.
앞으로도 개발을 할 때는 기획을 우선순위로 잡고 개발을 진행할 것이고,
기획 -> 설계 -> 코드 구현(개발) 을 더 체계적으로 실현할 수 있도록 많은 시간 개발을 하면서 점차 능숙해져 나갈 것이다.
그리고 잊지말자, 기획, 설계, 개발에는 답이 없으며, 상황에 따라 적합하게 활용하는 것이라는 걸
# 이번 주차 실습과제 평가
에러를 제외하면, 이번 실습은 내게 생각보다 쉬웠고, 앞으로는 에러를 대하는 자세를 더 굳게 다져서 어떤 에러든
빠르게 원인을 찾는 개발자로 성장해보자라는 다짐을 하게 되는 뜻 깊은 경험이었다.
'📚 스터디 > 프론트엔드' 카테고리의 다른 글
[안드로이드] 6주차 실습: BottomNavigation & ViewPager2 - TabLayout (0) | 2022.11.06 |
---|---|
[안드로이드] 5주차 실습: RecyclerView 사용 (5) | 2022.11.05 |
[안드로이드] 6주차: 고급 Layout과 View (0) | 2022.11.05 |
[안드로이드] 4주차: LifeCycle, 외부 작용으로의 Activity 예외처리 (2) | 2022.10.24 |
[안드로이드] 3주차: Activity 전환 & Fragment 전환 (0) | 2022.10.10 |