sean.jin
Spark Code Blog
sean.jin
전체 방문자
오늘
어제
  • 분류 전체보기
    • 개발공부
      • Kotlin
      • LeetCode
      • Algorithm
      • React
    • 주식차트
    • 책리뷰
    • 유틸리티

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 자기개발
  • 쿼드러플위칭데이
  • 경제
  • 책추천
  • 책리뷰
  • 책
  • 주식책리뷰
  • 트리플 위칭데이
  • 아빠와 딸의 주식투자 레슨
  • 초보
  • 오
  • 주식입문자
  • 네마녀의날
  • 부의 추월차선
  • 변동성
  • 주식투자

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
sean.jin

Spark Code Blog

[Kotlin] RecyclerView에 LiveData/ViewModel 적용하기 - 화면전환후 데이터유지 - RecyclerView 3
개발공부/Kotlin

[Kotlin] RecyclerView에 LiveData/ViewModel 적용하기 - 화면전환후 데이터유지 - RecyclerView 3

2021. 5. 29. 10:54
반응형
[Kotlin] RecyclerView에 LiveData/ViewModel 적용하기

목표

 

전 포스트에서 Recyclerview에 item을 추가 삭제할 수 있는 기능을 구현해봤는데요, 화면 UI가 변경될 때 뷰가 초기화되는 현상이 있었습니다. 이 문제를 해결하기 위해 이 포스트에서는 LiveData와 ViewModel을 이용해 UI 관련 데이터를 한 곳에서 제어할 수 있는 ViewModel을 만들어 UI가 다시 만들어져도 데이터가 초기화되지 않도록 해보겠습니다. (뷰바인딩에 익숙하지 않으시다면 아래 링크되어있는 전 포스트를 보고 오시는 것을 추천합니다.)

 

[Kotlin] RecyclerView에 setOnClickListener 추가 삭제하기 - RecyclerView 2

RecyclerView에 setonClickListener 추가 삭제하기 - RecyclerView 2 전 포스트에서 Recyclerview에 Viewbinding을 적용했는데요, 이번 포스트에서는 뷰 바인딩이 적용된 리사이클러뷰에 버튼을 눌러서 항목을 지..

underdog11.tistory.com

 

ViewModel 이해

  • 아래 이미지는 android developer에 있는 기존 라이프 사이클과 Viewmodel라이프 사이클의 비교 이미지입니다. 

  • 우리가 전에 만들었던 todoList에서는 데이터들이 onCreate에있어서, activity가 rotate 됐을 때 onDestroy에서 다시  oncreate에서 그려지는 과정에서 데이터가 리셋됨을 확인했습니다.  
  • ViewModel은 앱이 종료될때까지 살아있어서 lifecycle을 신경 써야 하는 고충을 해결해줍니다. 
  • 이번예제에서는 ViewModel을 사용해 UI가 변경되어도 data가 유지될수 있도록 하고
  • LiveData를 활용해 ViewModel에 있는 데이터가 추가되거나 제거됬을때 업데이트 되도록 해보겠습니다.

 

Dependencies 추가

  • buildGradle.app
android{
	kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {

    // ViewModel
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1")
    // LiveData
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.3.1")
    //KTX
    implementation "androidx.fragment:fragment-ktx:1.3.3"
}

ViewModel 만들어주기

  • 이해를 돕기위해 전 포스트에서 만든 ViewModel 적용전 코드입니다.

MainActivity / TodoRecyclerAdapter

  • Mainactivity를 보면 데이터를 수정하는 addTaskfunction과 deleteTask가 onCreate 안에서 실행되고있는것을 볼수있습니다. 
  • addTask, deleteTask function을 ViewModel로 이동을 하여 데이터 관련 함수들은 모두 Viewmodel에서 사용할수있도록 하겠습니다. (MainActivity아래에 만들었습니다.)
class MyViewModel : ViewModel() {
    val data = arrayListOf<Todo>() //class MainActivity에있던 val data를 ViewModel로 가져옵니다.

// mainactivity에있던 데이터관련 function들을 가져옵니다.

//수정전 시작
//	fun addTask() { 
//    	val todo = Todo(binding.editText.text.toString()) //Todo를 밖에서 가져오도록 바꿉니다.
//    	data.add(todo)
//    	binding.recyclerView.adapter?.notifyDataSetChanged() 더이상 바인드를 access할수없게되므로 지웁니다.
//  } 

//	fun deleteTask(todo: Todo) {
//    	data.remove(todo)
//    	binding.recyclerView.adapter?.notifyDataSetChanged() addtask와 똑같이 지워줍니다.
//}


//수정전 끝

//수정후 시작
    fun addTask(todo:Todo) {//
        data.add(todo)
       	//norifyDataSetChanged가 없어져서 UI로 업데이트를 할수없습니다. 
    }
    

    fun deleteTask(todo: Todo) {
        data.remove(todo)
    }
//수정후 끝

ViewModel에 LiveData 추가하기

  • addTask와 deleteTask 함수들이 Viewmodel에들어가면서 binding.recyclerView.Adapter?.notifyDataSetChanged()를 사용할수없게되면서, UI에 바뀐데이터를 업데이트해줄 코드가 없어진걸 확인할수있습니다. 
  • 그래서 UI업데이트를 해주기위해 LiveData를 추가해줘야합니다.
  • LiveData는 관찰/변경 가능하기 때문에 val data에있었던 데이터들을 변경이있을때마다 todoLiveData로 업데이트를 해주겠습니다.
class MyViewModel : ViewModel() {

//추가 시작
    val todoLiveData = MutableLiveData<List<Todo>>() //변경/관찰가능한 List<Todo>타입에 LiveData
//추가 끝
    private val data = arrayListOf<Todo>()

    fun toggleTodo(todo:Todo){
        todo.isDone = !todo.isDone
        todoLiveData.value = data
    }

    fun addTask(todo:Todo) {
        data.add(todo)
//추가시작
        todoLiveData.value = data //todoLiveData를 add된 데이터로 변경
//추가 끝
    }

    fun deleteTask(todo: Todo) {
        data.remove(todo)
//추가시작
        todoLiveData.value = data //todoLiveData를 remove된 데이터로 변경, 이제 TodoLiveData로 UI값을 변경해줘야한다.
//추가 끝    
    }
  • 이렇게 ViewModel에 Livedata적용은 끝났습니다.

LiveData를 MainActivity - onCreate로 불러오기

  • 앞에서 말했듯이 LiveData는 관찰과 변경이 가능합니다. 그래서 데이터가 변할때 관찰을 onCreate에서 하게 해서 UI가 다시만들어지거나 변할때 기존데이터와 업데이트되는 데이터를 불러오게 하겠습니다. 
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    private val viewModel: MyViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)


        binding.recyclerView.layoutManager = LinearLayoutManager(this)
        binding.recyclerView.adapter = TodoAdapter(
            emptyList(),
            onClickDeleteIcon = { 
                viewModel.deleteTask(it)
//제거              binding.recyclerView.adapter?.notifyDataSetChanged() LiveData로 UI업데이트를 해줄거기때문에 이제 필요없습니다.
            }

        )

        binding.addButton.setOnClickListener {
            val todo = Todo(binding.editText.text.toString())
            viewModel.addTask(todo)
//제거          binding.recyclerView.adapter?.notifyDataSetChanged()
        }
//추가시작
        //관찰UI업데이트
        viewModel.todoLiveData.observe(this, Observer { //viewmodel에서 만든 변경관찰 가능한todoLiveData를 가져온다.
            (binding.recyclerView.adapter as TodoAdapter).setData(it) //setData함수는 TodoAdapter에서 추가하겠습니다.
           
        })

    }
//추가끝




}

RecyclerAdapter에 setData함수만들기

  • setData라는 함수를 Adapter안에 구현해서, 이함수에 LiveData를 recyclerAdapter로 가져온후 기존데이터를 새로운데이터로 바꿔주도록 기능을만듭니다. 그리고 위에 관찰 UI에서 실행하도록 합니다.
class TodoAdapter(
    private var mydataSet: List<Todo>,
    val onClickDeleteIcon: (todo: Todo) -> Unit
) :
    RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() {

    class TodoViewHolder(val binding: ItemTodoBinding) :
        RecyclerView.ViewHolder(binding.root) { //아이템을 만들때 여러 뷰가있기때문에 itemTodobinding으로 가져온다.

    }


    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): TodoViewHolder {
        val view = LayoutInflater.from(viewGroup.context)
            .inflate(R.layout.item_todo, viewGroup, false) //내가 각아이템에 사용하는 view

        return TodoViewHolder(ItemTodoBinding.bind(view))
    }

    override fun onBindViewHolder(todoViewHolder: TodoViewHolder, position: Int) {//item을 화면에 표시해주는
        val listposition = mydataSet[position]
        todoViewHolder.binding.todoText.text = listposition.text
        todoViewHolder.binding.deleteImage.setOnClickListener {
            onClickDeleteIcon.invoke(listposition) //눌렀을때 listposition를 전달하면서 함수를 실행한다.
        }


    }

    override fun getItemCount() = mydataSet.size

//추가시작
    fun setData(newData:List<Todo>){
        mydataSet = newData
        notifyDataSetChanged()
    }
    
//추가 끝



}

실행해보시면 화면전환후에도 TodoList들이 유지되는걸 볼수있습니다. 아래는 이전 포스트들입니다.

 

1편:[Kotlin] RecyclerView에 ViewBinding 적용하기 - RecyclerView 1

 

[Kotlin] RecyclerView에 ViewBinding 적용하기 - RecyclerView 1

[Kotlin] RecyclerView에 ViewBinding 적용하기 목표 ViewBinding 추가하기 buildGradle.app android{ viewBinding { enabled = true } } MainActivity onCreate을 Viewbinding으로 수정해주기 **AcivityMainBind..

underdog11.tistory.com

2편:[Kotlin] RecyclerView에 setOnClickListener 추가 삭제하기 - RecyclerView 2


 

 

 

 

 

 

반응형

'개발공부 > Kotlin' 카테고리의 다른 글

[Kotlin] Collection 정리 list, set, map 차이 - HashMap, hashmapof, mutableMap, setOf, mutableSetOf,ArrayListof,listof 사용법 및 차이  (0) 2021.06.10
[Kotlin] Google AdMob 앱 수익창출 - 광고 달기 배너달기 / 버튼클릭시 전면광고  (0) 2021.06.03
[Kotlin] Material Design Date Picker - 날짜 선택기 사용법, 특정 구간날짜 비활성화  (0) 2021.05.31
[Kotlin] RecyclerView에 setOnClickListener 추가 삭제하기 - RecyclerView 2  (0) 2021.05.28
[Kotlin] RecyclerView에 ViewBinding 적용하기 - RecyclerView 1  (0) 2021.05.28
    '개발공부/Kotlin' 카테고리의 다른 글
    • [Kotlin] Google AdMob 앱 수익창출 - 광고 달기 배너달기 / 버튼클릭시 전면광고
    • [Kotlin] Material Design Date Picker - 날짜 선택기 사용법, 특정 구간날짜 비활성화
    • [Kotlin] RecyclerView에 setOnClickListener 추가 삭제하기 - RecyclerView 2
    • [Kotlin] RecyclerView에 ViewBinding 적용하기 - RecyclerView 1
    sean.jin
    sean.jin
    앱개발, 알고리즘, JS, Kotlin, 미국 취업준비

    티스토리툴바