TECHIT 앱 스쿨 2기: Android 35일차 (23.06.16)
자료 출처 : 안드로이드 앱스쿨 2기 윤재성 강사님 수업 내용
부끄럽지만 오늘 오전동안 정신 못차리고 졸았기에 강사님께서 말씀해주신 내용을 제대로 듣지 못하였습니다.
원인을 서술하자면 며칠 전 저의 뻘짓으로 깃허브 복구하느라 늦게 잔 점과 어제 특강이 있는 것을 깜빡하고 밀린 복습과 어제 배운 내용을 복습하는 계획의 시간이 미루어져... 또 다시 늦게 잠들었더니 오늘 오전에 저의 체력이 받쳐주지 못하고 오전 내내 졸다가 점심시간까지 점심을 안먹고 졸았습니다....ㅠㅜ 이제 순수 개념에 대한 수업일 수 만을 체크하면 16일 정도 남았는데 남은 개념에 대한 수업일 및 프로젝트 기간동안 컨디션 조절을 최소한 오늘처럼 되지 않을 정도로 관리하면서 집중하여 나아 갈 수 있도록 하겠습니다.
따라서 오늘 메뉴에 관한 내용은 강사님이 작성해주신 코드를 분석하여 작성하는 내용과 서적 및 구글링을 통하여 작성하였습니다.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
오늘의 시작은 메뉴에 관하여 설명 및 실습으로 시작하였습니다.
Option Menu : 앱의 액션바 또는 액티비티의 툴바에 표시되는 메뉴입니다. 사용자가 앱의 기능을 선택하거나 설정을 변경할 수 있는 메뉴를 제공하는 데 사용됩니다.
Option Menu을 구성하기 위한 단계 입니다.
XML 파일로 부터 메뉴를 생성하여 사용하는 경우
1. 메뉴 리소스 파일을 작성합니다.
1-1. res/menu 디렉토리에 XML 파일을 생성합니다.
1-2 . 1-1에서 만든 파일에 메뉴 항목을 정의합니다.
2. 메뉴 항목 추가 : XML 파일에 <menu> 요소를 사용하여 메뉴 항목을 추가합니다.
각 항목은 <item> 요소로 정의되며, 속성값으로 아이콘, 제목등을 지정할 수 있습니다.
3. 액티비티에서 Option Menu를 활성화 한다.
3-1. 액티비티의 onCreateOptionsMenu() 메서드를 오버라이딩 하여 Option Menu 를 활성화 시킨다.
3-2. 오버라이딩 한 메서드에서 menuInflater.inflate() 메서드를 호출하여 메뉴 리소스 파일을 팽창 시키고,
true를 반환합니다.
package com.test.android39_menu_study
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.Menu
import com.test.android39_menu_study.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
lateinit var activityMainBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(activityMainBinding.root)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.option_menu,menu)
return true
}
}
코드를 이용하여 메뉴를 구성하는 경우
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menu?.add(Menu.NONE,Menu.NONE + 1, Menu.NONE, "코드 메뉴1")
menu?.add(Menu.NONE,Menu.NONE + 2, Menu.NONE, "코드 메뉴2")
val subMenu = menu?.addSubMenu("코드 메뉴3")
subMenu?.add(Menu.NONE, Menu.NONE + 3, Menu.NONE, "코드 메뉴 3-1")
return true
}
여기서 add() 함수에 4개의 매개변수를 전달해줘야 합니다.
add(groupId: Int, itemId: Int, order: Int, title: CharSequence)
groupId: 메뉴 항목이 속할 그룹의 식별자를 나타냅니다. 일반적으로 Menu.NONE을 사용하여 그룹을 지정하지 않는 경우가 많습니다. 그룹 식별자는 필요에 따라 메뉴 항목을 그룹화하고 조작할 때 사용됩니다.
itemId: 메뉴 항목의 식별자를 나타냅니다. 이 식별자를 사용하여 선택 이벤트를 처리하거나 항목을 구분할 수 있습니다. 식별자는 R.id 형식으로 정의된 리소스 ID를 사용할 수 있습니다.
order: 항목의 순서를 지정하는 정수 값입니다. 일반적으로 Menu.NONE을 사용하여 순서를 지정하지 않는 경우가 많습니다. 순서 값은 항목이 Option Menu에서 표시되는 순서를 제어하는 데 사용됩니다.
title: 메뉴 항목의 제목을 나타냅니다. CharSequence 형식으로 제공되며, 문자열 리소스나 직접 문자열 값을 사용할 수 있습니다.
메뉴 항목에 대하여 선택 처리
메뉴항목이 선택될 때의 동작을 처리할 경우에는 액티비티에서 onOptionsItemSelected() 메서드를 오버라이드 하여
메뉴 항목이 선택 될 때의 동장을 처리합니다. 메뉴 항목은 객체로 전달되며, itemId를 사용하여 항목을 식별할 수 있습니다.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
activityMainBinding.run{
when(item.itemId){
Menu.FIRST + 1 ->{
textView.text = "첫 번째 옵션을 선택하였습니다."
}
Menu.FIRST + 2 ->{
textView.text = "두 번째 옵션을 선택하였습니다."
}
Menu.FIRST + 3 ->{
textView.text = "세 번째 옵션을 선택하였습니다."
}
}
}
return super.onOptionsItemSelected(item)
}
다음으로는 Popup Menu 에 대해서 알려주셨습니다.
Popup Menu : 개발자가 원할 때 원하는 곳에 띄울 수 있는 메뉴 입니다. 즉, 사용자가 특정 요소를 길게 누르거나 클릭하면 표시되는 작은 메뉴입니다. 주로 사용자가 요소와 관련된 작업을 선택하거나 추가적인 옵션을 제공하는 데 사용됩니다.
일반적으로는 액티비티의 특정 뷰에 연결되어 표시됩니다.
Popup Menu 구성하는 단계
1. 메뉴 리소스 파일 작성
res/menu 디렉토리에 XML 파일을 생성하여 팝업 메뉴의 항목을 정의합니다.
2. 팝업 메뉴를 표시할 뷰 설정
팝업 메뉴를 표시할 뷰(버튼, 이미지뷰 등)를 찾아 설정합니다. 이 뷰에 팝업 메뉴를 연결하여 터치 이벤트를 처리할 수 있도록 해야 합니다.
3 . 팝업 메뉴 생성 및 이벤트 처리
해당 뷰에 대한 롱클릭 리스너나 클릭 리스너를 등록하여 팝업 메뉴를 생성하고 이벤트를 처리합니다. 팝업 메뉴를 생성하기 위해 PopupMenu 클래스를 사용할 수 있습니다.
activityMainBinding.run {
buttonPopupMenu.setOnClickListener {
// 첫번째 매개 변수로는 생성되는 액티비티를 전달한다.
// 두번째 매개 변수로는 액티비티에서 해당 팝업메뉴가 나올 View를 전달한다.
val popupMenu = PopupMenu(this@MainActivity, textView)
// 메뉴를 구성한다.
// 첫번째 매개 변수 : 해당 메뉴의 레이아웃 파일 위치
// 두번째 매개 변수 : 해당 메뉴의 정보를 가지고 있는 객체의 menu
menuInflater.inflate(R.menu.popup_menu, popupMenu.menu)
// 팝업메뉴를 띄운다.
popupMenu.show()
// 팝업메뉴 중 특정 메뉴를 눌렀을때 동작하는 리스너
popupMenu.setOnMenuItemClickListener {
when(it.itemId){
R.id.pop1 -> textView.text = "팝업메뉴 1 선택"
R.id.pop2 -> textView.text = "팝업메뉴 2 선택"
R.id.pop3 -> textView.text = "팝업메뉴 3 선택"
}
true
}
}
}
다음으로는 컨텍스트 메뉴에 대해서 알려주셨습니다.
Context Menu
안드로이드 앱에서 사용자가 특정 항목을 길게 누르거나 클릭했을 때 표시되는 메뉴입니다. 주로 리스트뷰, 그리드뷰 등의 항목에 대한 추가 작업이나 조작을 제공하는 데 사용됩니다.
Context Menu 구성하는 단계
1. onCreateContextMenu() 메서드를 오버라이드하여 컨텍스트 메뉴를 생성합니다. 이 메서드는 컨텍스트 메뉴가 처음으로 열릴 때 호출됩니다.
2. onContextItemSelected() 메서드를 오버라이드하여 컨텍스트 메뉴 항목의 선택 이벤트를 처리합니다. 이 메서드는 사용자가 컨텍스트 메뉴의 항목을 선택할 때 호출됩니다.
주요 부분 코드
activityMainBinding.run {
registerForContextMenu(textViewContextSelect)
registerForContextMenu(listView)
listView.run{
adapter = ArrayAdapter<String>(
this@MainActivity, android.R.layout.simple_list_item_1, dataList
)
}
}
// v : 사용자가 길게 누르면 뷰 객체가 들어온다.
override fun onCreateContextMenu(
menu: ContextMenu?,
v: View?,
menuInfo: ContextMenu.ContextMenuInfo?
) {
super.onCreateContextMenu(menu, v, menuInfo)
// View의 아이디로 분기한다.
v?.run {
when(v.id){
R.id.textViewContextSelect -> {
// 메뉴의 제목
menu?.setHeaderTitle("텍스트 뷰의 메뉴")
// 첫번째 매개 변수 : 해당 메뉴의 레이아웃 파일 위치
// 두번째 매개 변수 : 해당 메뉴의 정보를 가지고 있는 객체의 menu
menuInflater.inflate(R.menu.context_menu,menu)
}
R.id.listView ->{
// 별도 기재
val info = menuInfo as AdapterView.AdapterContextMenuInfo
menu?.setHeaderTitle("${dataList[info.position]}의 메뉴")
menuInflater.inflate(R.menu.list_menu,menu)
}
}
}
}
// 컨텍스트 메뉴의 항목을 선택하였을 때 호출되는 메서드
// 해당 메서드에서는 메뉴를 띄우기 위해 길게 누를 뷰가 무엇인지 구분할 방법이 없기 때문에
// 이에 서로 다른 뷰의 컨텍트스 메뉴라고 하더라도 메뉴의 id는 모두 다 다르게 구성해줘야 한다.
override fun onContextItemSelected(item: MenuItem): Boolean {
when(item.itemId){
// TextView의 컨텍스트 메뉴
R.id.context1 -> activityMainBinding.textViewContextSelect.text = "텍스트뷰 - 메뉴1"
R.id.context2 -> activityMainBinding.textViewContextSelect.text = "텍스트뷰 - 메뉴2"
R.id.context3 -> activityMainBinding.textViewContextSelect.text = "텍스트뷰 - 메뉴3"
// ListView의 컨텍스트 메뉴
R.id.list_menu1 -> {
val info = item.menuInfo as AdapterView.AdapterContextMenuInfo
activityMainBinding.textViewContextSelect.text = "리스트뷰 - ${dataList[info.position]}의 메뉴1"
}
R.id.list_menu2 -> {
val info = item.menuInfo as AdapterView.AdapterContextMenuInfo
activityMainBinding.textViewContextSelect.text = "리스트뷰 - ${dataList[info.position]}의 메뉴2"
}
R.id.list_menu3 -> {
val info = item.menuInfo as AdapterView.AdapterContextMenuInfo
activityMainBinding.textViewContextSelect.text = "리스트뷰 - ${dataList[info.position]}의 메뉴3"
}
}
return super.onContextItemSelected(item)
}
`val info = item.menuInfo as AdapterView.AdapterContextMenuInfo`는 컨텍스트 메뉴에서 선택된 항목의 정보를 가져오기 위해 사용되는 코드입니다.
`item.menuInfo`는 사용자가 선택한 컨텍스트 메뉴 항목에 대한 추가 정보를 담고 있는 객체입니다. 이 정보는 AdapterView의 하위 클래스인 AdapterViewContextMenuInfo로 캐스팅되어 사용됩니다.
`AdapterViewContextMenuInfo` 객체에는 선택된 항목의 위치(position)와 관련된 다른 유용한 정보들도 포함되어 있습니다. 주로 리스트뷰에서 사용되며, 선택된 항목의 인덱스나 ID 등을 얻을 수 있습니다.
따라서 `val info = item.menuInfo as AdapterView.AdapterContextMenuInfo`를 사용하여 `info` 변수에 컨텍스트 메뉴에서 선택된 항목에 대한 정보를 할당합니다. 이를 통해 선택된 항목의 위치나 추가적인 데이터를 가져와서 원하는 동작을 수행할 수 있습니다.
다음으로는 리사이클러 뷰와 컨텍스트 메뉴를 이용하는 문제를 내주셨습니다.
문제는 하기와 같습니다.
문제에서 다른 부분은 지금까지 작성하였었던 문제와 동일하여 작성하는데 어려움은 없었습니다.
다만 삭제하는 부분에서 해당 자료의 위치를 가져오는 부분에서 어려움이 있었습니다. 그 부분에 대해서는 강사님이 알려주신 방법만 작성하도록 하겠습니다.
inner class ViewHolderClass(rowBinding: RowBinding) : RecyclerView.ViewHolder(rowBinding.root){
var textViewRow1:TextView
var textViewRow2:TextView
var textViewRow3:TextView
init{
textViewRow1 = rowBinding.textViewRow1
textViewRow2 = rowBinding.textViewRow2
textViewRow3 = rowBinding.textViewRow3
// 항목 하나의 View에 컨텍스트 메뉴 생성 이벤트를 붙혀준다.
rowBinding.root.setOnCreateContextMenuListener { menu, v, menuInfo ->
menu.setHeaderTitle("${dataList[adapterPosition].name}")
menuInflater.inflate(R.menu.row_menu, menu)
// 첫 번째 메뉴에 대한 이벤트 처리
menu[0].setOnMenuItemClickListener {
// 현재 항목 번째를 삭제한다.
dataList.removeAt(adapterPosition)
this@RecyclerViewAdpaterClass.notifyDataSetChanged()
false
}
}
}
}
강사님께서는 뷰 홀더 클래스를 생성하면서 해당 이벤트를 넣어서 데이터를 제거하는 방법을 알려주셨습니다.
adapterPosition
RecyclerView.ViewHolder 클래스에 속하는 속성입니다. 이 속성은 현재 ViewHolder가 RecyclerView의 어댑터에서 어떤 위치에 있는지를 나타내는 정수값입니다.
다음으로는 액티비티의 생명주기에 대해서 알려주셨습니다.
종료될 가능성프로세스 상태액티비티 상태
최소 | 포그라운드(포커스가 있거나 포커스를 가져올 예정) | 생성됨 시작됨 재개됨 |
더보기 | 백그라운드(포커스 상실) | 일시중지됨 |
최대 | 백그라운드(보이지 않음) | 중지됨 |
비우기 | 소멸됨 |
사진 & 표 출처 : https://developer.android.com/guide/components/activities/activity-lifecycle?hl=ko
활동 수명 주기에 관한 이해 | Android 개발자 | Android Developers
활동은 사용자가 전화 걸기, 사진 찍기, 이메일 보내기 또는 지도 보기와 같은 작업을 하기 위해 상호작용할 수 있는 화면을 제공하는 애플리케이션 구성요소입니다. 각 활동에는 사용자 인터페
developer.android.com
강사님께서는 해당 내용에 대해서 알기 쉬우면서도 자세하게 말씀해주셨습니다.
정리하자면 액티비티는 BackStack에 저장되며, 안드로이드 기종 스마트폰에 백버튼을 누르면 돌아가는 것은 정말로 이전 액티비티로 돌아가는 것이 아니라 현재 액티비티를 종료시켜 BackStack 가장 상단에 있는 액티비티가 나오는 것이라고 말씀해주셨습니다.
onCreate(): 액티비티가 생성될 때 호출되는 함수입니다. 액티비티의 초기화 작업을 수행하는 데 사용됩니다. 레이아웃 설정, 데이터 초기화, 리소스 로딩 등의 작업을 이곳에서 수행합니다.
onStart(): 액티비티가 사용자에게 표시되기 직전에 호출되는 함수입니다. 액티비티가 사용자에게 보여지기 전에 필요한 준비 작업을 수행할 수 있습니다. 이 단계에서 액티비티는 "활성화" 상태가 되었으며, 사용자와의 상호작용을 받을 수 있습니다.
onResume(): 액티비티가 사용자와 상호작용하기 시작할 때 호출되는 함수입니다. 액티비티가 포그라운드에 표시되며, 사용자 입력 및 애니메이션 등을 처리할 수 있습니다. 대부분의 초기화 작업은 onResume()에서 수행됩니다.
onPause(): 액티비티가 일시적으로 중단되거나 다른 액티비티가 화면을 가리는 경우 호출되는 함수입니다. 이 단계에서는 액티비티가 "일시 중지" 상태에 있으며, 더 이상 화면에 표시되지 않습니다. 사용자 입력을 처리하는 작업을 중지하거나, 리소스 해제 및 데이터 저장 등의 작업을 수행할 수 있습니다.
onStop(): 액티비티가 더 이상 사용자에게 보이지 않을 때 호출되는 함수입니다. 액티비티가 "정지" 상태에 있으며, 다른 액티비티가 전체 화면을 가리는 경우 호출됩니다. 여기서는 리소스 해제나 데이터 저장과 같은 작업을 수행할 수 있습니다.
onDestroy(): 액티비티가 소멸될 때 호출되는 함수입니다. 액티비티가 완전히 종료되기 전에 필요한 정리 작업을 수행합니다. 리소스의 해제, 미완료된 작업의 취소 등을 처리할 수 있습니다.
onRestart(): 액티비티가 onStop() 상태에서 다시 시작되는 경우 호출되는 함수입니다. 일반적으로 onStop() 이후에 액티비티가 다시 화면에 나타날 때 호출됩니다. 이 단계에서 액티비티는 "시작" 상태로 전환됩니다.
마무리
이후에 Intent 에 대해서도 배웠지만, 정말 조금만 배웠기에 추후 제대로 배운 후에 작성 할 수 있도록 하겠습니다.
오늘의 마음가짐
컨디션조절이 한번 망가지면 정말 영향이 큰 것 처럼, 추후 코드 작성 혹은 프로그램 작성에 있어서는 조금씩 쌓여 크리티컬 이슈가 생기지 않도록 하는 개발자가 되자