[Android] View model 사용하여 데이터 보존하기

Jinny·2021년 4월 2일
0

Android

목록 보기
26/32
post-thumbnail

오늘은 ViewModel을 사용하여 데이터를 유지하는 간단한 todoList 앱을 만들어 본다.

🚩 ViewModel이란?

ViewModel 클래스는 수명 주기를 고려하여 UI 관련 데이터를 저장하고 관리하도록 설계되어있다.

ViewModel 클래스를 사용하면 화면 회전과 같이 구성을 변경할 때도 데이터를 유지할 수 있다.

일반적인 방법으로 데이터를 관리 시 다음과 같이
기기의 회전 처리를 하면 데이터가 날아가는걸 확인 할 수 있다.

화면 회전 시 activity가 destroy후 create가 되기 때문이다.
이를 해결하기 위해 구글에서 제공해주는 View model을 사용해본다.

🔸 viewModel 추가하기

viewmodels() 사용을 위해 android-ktx를 추가해준다.

//build.gradle - dependencies에 추가해준다.
implementation "androidx.fragment:fragment-ktx:1.3.2" 

🔸 viewmodel 사용하기

(1) ViewModel 객체 생성

class MyViewModel : ViewModel() {
    private val users: MutableLiveData<List<User>> by lazy {
        MutableLiveData().also {
            loadUsers()
        }
    }

    fun getUsers(): LiveData<List<User>> {
        return users
    }

    private fun loadUsers() {
       
    }
}

(2) Activity에서 사용되도록 설정하기

class MyActivity : AppCompatActivity() {

private val viewModel: MainViewModel by viewModels()
    override fun onCreate(savedInstanceState: Bundle?) {
    	// 위 MyViewModel을 가져와 쓰겠다.
        val model: MyViewModel by viewModels()
        
        // 위 데이터를 observe(관찰)하겠다.
        model.getUsers().observe(this, Observer<List<User>>{ users ->
            // 업데이트 할 작업
        })
    }
}

크게는 위와 같이 설정하여 사용이 가능하다.
아래는 ViewModel을 사용한 TodoList 앱이다.

🚩 전체코드

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    //ViewModel 객체 선언
    private val viewModel: MainViewModel by viewModels()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        binding.rvItem.apply {
            layoutManager = LinearLayoutManager(this@MainActivity)
            adapter = TodoAdapter(viewModel.data, onClickDelete = {
            	//viewModel의 deleteTodo를 실행
                viewModel.deleteTodo(it)
                binding.rvItem.adapter?.notifyDataSetChanged()
            }, onClickItem = {
                viewModel.toggleTodo(it)
                binding.rvItem.adapter?.notifyDataSetChanged()
            })
        }

        binding.addBtn.setOnClickListener {
            val todo = Todo(binding.addEt.text.toString())
            viewModel.addTodo(todo)
            binding.rvItem.adapter?.notifyDataSetChanged()
        }
    }
}

data class Todo(
    val text: String,
    var isDone: Boolean = false
) //자동으로 게터세터가 생성된 dataclass ~!~!


class TodoAdapter(
    private var myDataset: List<Todo>,
    val onClickDelete: (todo: Todo) -> Unit,
    val onClickItem: (todo: Todo) -> Unit
) :
    RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() {
    class TodoViewHolder(val binding: ItemTodoBinding) : RecyclerView.ViewHolder(binding.root)
    //.root 하면 본인이 어떤 뷰로 부터 생성된 바인딩인지 확인 가능

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoAdapter.TodoViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_todo, parent, false)
        return TodoViewHolder(ItemTodoBinding.bind(view))
    }

    override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
        val todo = myDataset[position]
        holder.binding.tvList.text = todo.text
        if (todo.isDone) {
            holder.binding.tvList.apply {
                paintFlags = paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
                setTypeface(null, Typeface.ITALIC)
            }
        } else {
            holder.binding.tvList.apply {
                paintFlags = 0
                setTypeface(null, Typeface.NORMAL)
            }
        }
        holder.binding.ivDelete.setOnClickListener {
            onClickDelete.invoke(todo)
        }
        holder.binding.root.setOnClickListener {
            onClickItem.invoke(todo) //todo를 전달하여 onClickItem함수를 실행시킨다.
        }
    }

    override fun getItemCount(): Int = myDataset.size

}

class MainViewModel : ViewModel() {
    val data = arrayListOf<Todo>()
    fun toggleTodo(todo: Todo) {
        todo.isDone = !todo.isDone
    }

    fun addTodo(todo: Todo) {
        data.add(todo)
    }

    fun deleteTodo(todo: Todo) {
        data.remove(todo)
    }
}

👩‍💻 결과

화면 회전시에도 UI의 데이터가 남아있는것을 확인 할 수 있다.


출처 : 안드로이드 공식문서 - ViewModel
profile
신입 개발자👩‍💻

0개의 댓글