Android/StoreInfo

<정리> 챌린지반 과제2 - 2

re트 2024. 1. 23. 14:28
728x90

저번까지 한 것에 이어서 선택과제였던 할일 등록 기능을 MVVM 패턴으로 구현하는 걸 혼자서 해보았다.

힌트에 기반하여 저번 코드에서 변경된 부분과 추가된 부분이 있다.

 

[깃허브]

https://github.com/heesoo-park/ChallengeRecruitAssignment/tree/week1_contain_MVVM

 

1. 할일 저장소 생성

각각의 프래그먼트에서 사용하던 더미데이터를 object 클래스인 DataStore로 모았다.

그리고 거기서 함수를 만들어 할일을 추가할 수 있도록 했다.

object DataStore {
    private val totalTodoList: ArrayList<Todo> = ArrayList()

    init {
        totalTodoList.add(
            Todo(
                "title 0",
                "description 0"
            )
        )
        totalTodoList.add(
            Todo(
                "title 1",
                "description 1"
            )
        )
        totalTodoList.add(
            Todo(
                "title 2",
                "description 2"
            )
        )
    }

    fun getTotalTodoList(): ArrayList<Todo> {
        return totalTodoList
    }

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

 

2. 플로팅 액션 버튼 위치 변경

튜터님의 힌트에 프래그먼트에서 registerForActivityResult를 사용하라는 게 있어서 플로팅 액션 버튼을 메인 액티비티에서 Todo 프래그먼트로 이동했다.

그래서 context가 필요한 부분에 requireContext()를 사용했다.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    ...

    binding.fabTodoAdd.setOnClickListener {
        val intent = Intent(requireContext(), RegisterTodoActivity::class.java)
        resultLauncher.launch(intent)
    }
}

 

3. Todo 등록 액티비티에서 입력값 보내고 Todo 프래그먼트에서 받기

등록 버튼을 눌렀을 때 EditText에 입력된 값을 인텐트를 통해 보내줬다.

값은 데이터클래스를 Parcelize해서 객체 자체를 보낼 수 있게 했다.

binding.btnRegisterTodoRegister.setOnClickListener {
    val newIntent = Intent()
    newIntent.putExtra("todo", Todo(binding.etRegisterTodoTitle.text.toString(), binding.etRegisterTodoDescription.text.toString()))
    setResult(RESULT_OK, newIntent)
    finish()
}

이건 프래그먼트에서 registerForActivitResult를 통해 받는다.

class TodoFragment : Fragment() {

    private lateinit var resultLauncher: ActivityResultLauncher<Intent>

    ...

    override fun onAttach(context: Context) {
        super.onAttach(context)
        resultLauncher =
            registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
                if (result.resultCode == RESULT_OK) {
                    result?.data?.getParcelableExtra("todo", Todo::class.java)
                        ?.let { viewModel.onClickRegister(it) }
                }
            }
    }

    ...

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        ...

        binding.fabTodoAdd.setOnClickListener {
            val intent = Intent(requireContext(), RegisterTodoActivity::class.java)
            resultLauncher.launch(intent)
        }
    }
}

그리고 뷰모델의 onClickRegister 함수를 호출한다.

 

4. 뷰모델 생성

MVVM 패턴을 적용해야했기에 VIewModel을 만들었다.

새로운 할일이 들어왔음을 알려주는 LiveData를 만들고 변경이 생겼을 때 프래그먼트의 리사이클러뷰 adapter에 notify해줬다.

class TodoViewModel : ViewModel() {

    private val _newTodo: MutableLiveData<Todo> = MutableLiveData()
    val newTodo: LiveData<Todo> get() = _newTodo

    fun onClickRegister(todo: Todo) {
        DataStore.addTodo(todo)
        _newTodo.value = todo
    }
}
private val viewModel by lazy {
    ViewModelProvider(this@TodoFragment)[TodoViewModel::class.java]
}

private fun initViewModel() = with(viewModel) {
    newTodo.observe(viewLifecycleOwner) {
        adapter.notifyItemInserted(DataStore.getTotalTodoList().lastIndex)
    }
}
반응형