지난 포스트
목표
이 포스트는 총 5편으로 이루어져 있습니다. 밑줄 친 항목이 이번 포스트에서 다룰 항목 입니다.
RoomDatabase 개념
Roomdatabase의 기본 요소인 Entity, Database, Dao 개념/구현 (1편)LiveData, ViewModel, Repository를 이용하여 MVVM 아키텍처 구성(1편)
Insert 구성
- Navigation Graph , NavHostFragment추가(2편)
- 각 list, update, add fragment의 layout 및 프래그먼트 구현(2편)
- Add Fragment를 여는 플로팅 버튼 추가 (2편)
- DB browser를 통해 database 확인(2편)
- RecyclerView에 들어갈 ItemLayout과 ListAdapter 추가(3편)
- RecyclerView와 LiveData 적용하기(3편)
- 위와 같이 Room database에 저장된 값을 Recyclerview와 연결하기 (3편)
Update 구성
- Update layout 생성(4편)
- Update Layout Navigation Graph에 연결(4편)
- Navigation Argument 추가하기(4편)
- 데이터베이스에 수정된 값 업데이트(4편)
Delete 구성
- 제거 버튼 Action bar에 추가(5편)
- 선택한 데이터 삭제(5편)
- 모든 데이터 삭제(5편)
Navigation Graph, NavHostFragment 추가
우리는 보통 버튼을 눌렀을때 새 프라그먼트나 activity가 열릴떄 Intent를 사용해주었습니다. 그런데 이런 상호작용이 많게되면, 햇갈리게되는데 이때 사용하는게 Navigation Graph와 NavHostFragment입니다. 이 요소를 추가해주면, 여러 프래그먼트끼리 상호작용을 표현할때 편합니다. Android stuido가 UI를 제공하기때문에 쉽게 프라그먼트끼리 상호작용을 표현할수있습니다.
더 자세히 알고싶으시다면, navigation graph를 활용하여 제가 하단네비게이션을 구현한 포스트를 보고오시면 도움되실겁니다.
Navigation Graph를 만들어 주기위해 RES폴더 아래에 navigation 파일을 만들어주겠습니다.
- res/navigation
먼저 Destination을 추가해줘야합니다. + 아이콘을 선택후 Create New Destination을 클릭해주면 아래와같은 창이나옵니다.
같은방식으로 ListFragment, AddFragment, UpdateFragment를 추가해줍니다.
3개를 모두 추가해주시면 아래와같이 각 fragment창이 보이게 됩니다. 그리고 마우스를 올리게되면 동그란 표시가보이게되는데 이걸 드래그해서 다른 프래그먼트에 올리면 연결되게됩니다.
아래와같이 ListFragment ↔ addFragment 와 updateFragment ↔ ListFragment를 연결해주시면됩니다.
각 Activity 와 layout들이 만들어진걸 확인하실수있습니다.
이렇게하면 navigation graph준비는 끝납니다.
Fragment/Layout 추가
Fragment정리
Fragment에 코드를 넣어주기전에 패키지들을 만들어서 정리를 하고 시작하겠습니다. 아래와 같이 패키지에 파일들을 넣어주세요
위에 3개의 fragment를 추가해줬기때문에 새로운 패기지를 만들어서 다시 나열해보겠습니다.
NavHost Fragment 추가
NavHostFragment를 사용하여 우리가 만들어준 navigation graph가 작동할 위치에 넣어주겠습니다.
activitymain에서 작동하게 될것이기때문에 activity_main으로 갑니다.
- res/layout/activity_main
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
android:id="@+id/fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="409dp"
android:layout_height="729dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/my_nav" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_main에 있는 navhostfragment에 destination은 list fragment입니다. listfragment에서 항목을 클릭했을때 updateFragment와 addFragment가 나오도록 navgraph에서 연결해주었기때문입니다.
listFragment 추가
navgraph에서 destination인 list fragment먼저 레이아웃을 추가해보겠습니다.
- res/layout/fragment_list
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.list.ListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:padding="25dp"
android:layout_width="409dp"
android:layout_height="729dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="53dp"
android:layout_height="56dp"
android:layout_marginEnd="28dp"
android:layout_marginBottom="56dp"
android:clickable="true"
android:src="@android:drawable/ic_menu_add" //벡터 아이콘 추가
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
데이터베이스에 있는 항목들이 들어갈 recyclerview와 floating버튼이 들어가게됩니다.
플로팅 버튼에 벡터 아이콘을 추가해주었습니다. 디자인요소이기 때문에 스킵하겠습니다.
다시 activity_main을 확인해보면 listfragment의 프리뷰를 확인 하실수있습니다.
MainActivity
onSupportNavigateUp 을 추가해줍니다.
class MainActivity : AppCompatActivity() {
//
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupActionBarWithNavController(findNavController(R.id.fragment))
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.fragment)
return navController.navigateUp() || super.onSupportNavigateUp()
}
}
Floating button 추가
fragmentlist에 만들어준 floating button을 클리하면 add fragment가 나오도록 해보겠습니다.
- res/layout/fragment_add
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragments.add.AddFragment">
<EditText
android:id="@+id/editTextTextPersonName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="88dp"
android:ems="10"
android:hint="First Name"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/editTextTextPersonName2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Last Name"
android:inputType="textPersonName"
app:layout_constraintStart_toStartOf="@+id/editTextTextPersonName"
app:layout_constraintTop_toBottomOf="@+id/editTextTextPersonName" />
<EditText
android:id="@+id/editTextNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:hint="age"
android:inputType="number"
app:layout_constraintStart_toStartOf="@+id/editTextTextPersonName2"
app:layout_constraintTop_toBottomOf="@+id/editTextTextPersonName2" />
<Button
android:id="@+id/add_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="56dp"
android:text="Button"
app:layout_constraintEnd_toEndOf="@+id/editTextNumber"
app:layout_constraintStart_toStartOf="@+id/editTextNumber"
app:layout_constraintTop_toBottomOf="@+id/editTextNumber" />
- fragments/ListFragment
플로팅 버튼에 setonclicklistener을 달아주었습니다.
class ListFragment : Fragment() {
private lateinit var mUserViewModel: UserViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_list, container, false) //뷰와 연결해줍니다.
view.floatingActionButton.setOnClickListener{//플로팅 버튼을 설정해줍니다.
findNavController().navigate(R.id.action_listFragment_to_addFragment) //플로팅 버튼을 누르면 addFragment로 화면전환합니다.
}
}
- MainActivity
navController를 actionbar에 달아줌으로써 플로팅 버튼이 작동하게 합니다.
class MainActivity : AppCompatActivity() {
//
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupActionBarWithNavController(findNavController(R.id.fragment))//actionbar
}
}
Add Fragment
add프래그먼트에 사용자가 editText로 넣은 값을 User 데이터 클래스 형식으로 viewmodel에 넣어주도록 하겠습니다.
아래 코멘트를 확인해주세요.
class AddFragment : Fragment() {
//뷰모델을 이니셜라이즈 해줍니다.
private lateinit var mUserViewModel: UserViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// add 프라그먼트를 불러옵니다.
val view = inflater.inflate(R.layout.fragment_add, container, false)
//뷰모델 프로바이더를 실행해줍니다.
mUserViewModel = ViewModelProvider(this).get(UserViewModel::class.java)
//버튼을 누르면 insertDataToDatabase가 실행됩ㄴ디ㅏ.
view.add_button.setOnClickListener{
insertDataToDatabase()
}
return view
}
private fun insertDataToDatabase() {
//사용자가 입력한 텍스트들을 가져옵니다.
val firstName = editTextTextPersonName.text.toString()
val lastName = editTextTextPersonName2.text.toString()
val age = editTextNumber.text
if(inputCheck(firstName,lastName,age)){ //inputcheck라는 함수를 만들어주었습니다.
//유저 오브젝트를 만들어줍니다.이 값이 database에 전송되게 됩니다.
val user = User(0,firstName, lastName, Integer.parseInt(age.toString()))
//id가 0인 이유는 우리가 PK를 자동으로 생성되게 만들어도 값을 넣어줘야합니다.
//뷰모델에 add user를 해줌으로써 데이터베이스에 user값을 넣어주게 됩니다.
mUserViewModel.addUser(user)
//토스트 메세지입니다.
Toast.makeText(requireContext(),"Successfully added!", Toast.LENGTH_LONG).show()
//다시 listfragment로 돌려보냅니다.
findNavController().navigate(R.id.action_addFragment_to_listFragment)
}else{
//만약 유저가 editText모두 넣지 않았다면 토스트 메세지를 띄웁니다.
Toast.makeText(requireContext(), "Please fill out all fields.", Toast.LENGTH_LONG).show()
}
}
//텍스트박스가 비어있는지 확인합니다.
private fun inputCheck(firstName:String, lastName:String, age:Editable):Boolean{
return !(TextUtils.isEmpty(firstName)&&TextUtils.isEmpty(lastName)&& age.isEmpty())
}
}
DB browser를 통해 database 확인
DB browser를 통해 database에 데이터가 잘 들어갔는지 확인해보겠습니다.
1. DB browser다운로드
DB browser를 다운로드 해줍니다.
2. 디바이스에서 DB 파일
먼저 디바이스에 앱을 실행 시켜줍니다.
Device File Explorer로 들어가서 디바이스 데이터 베이스에 접근해줍니다.
data/data로 들어가서 이 앱에 파일을 찾습니다.
제 앱의 이름은 com.tassiecomp.roomdatabasepractice입니다.
그리고 데이터베이스 안에 3개파일을 바탕화면에 저장해주겠습니다.
DB browser을 열어줍니다.
그리고 open Database를 해주고 All files로 바꿔준후 android studio에서 가져온 user_database 파일을 찾습니다.
아래와같이 Browse data로 보면 우리가 저장했던 데이터가 보이게 됩니다.
다음편에서는 이렇게 저장된 데이터를 recyclerview에 연결해보도록 하겠습니다.