[팀 프로젝트]세 번째 코드 리뷰 (작성자-2)

HEETAE HEO·2022년 3월 22일
0
post-thumbnail

저번 글에 이어 마저 코드를 설명하겠습니다.

CSFragment

CSFragment는 고객센터에서 자주 질의되는 내용들을 모아 사용자에게 보여주는 화면으로 사용자들이 전화난 Email로 고객센터에 문의하기전 찾고있던 질의가 있는지 확인하는데 사용된다.

이 화면의 구역에는 ViewPager2가 적용되어 있는데 간단하게 ViewPager에 대해 설명하겠습니다.

ViewPager

: 화면 슬라이드에 자동으로 애니메이션을 적용할 수 있는 객체이다.

이 말은 한 화면에서 범위내의 부분에서 좌우 또는 상하로 화면전환을 할 수 있다는 것이다.

다음 영상과 같이 좌우로 애니메이션 동작을 한다.

이러한 ViewPager2에다가 RecyclerView를 생성하여 데이터를 입력하면 일반적으로 많이 사용하고 있는 배달 플랫폼의 음식점들을 구경할 때 음식점 카테고리의 변경을 위해 터치로 움직이는 경우도 있지만 음식점 리스트를 옆으로 넘겨 카테고리를 변경하기도 한다. 그러한 동작을 도와주는 것이 ViewPager2이다.

ViewPager2 코드를 본다면

private lateinit var viewAdapter : HomeListFragmentPagerAdapter

if (::viewAdapter.isInitialized.not()) { 
            val csCategory = CSCategory.values() 

            val CSListfragmnet = csCategory.map {
                CSListFragment.newInstance(it)
            }

            viewPagerCs.adapter = HomeListFragmentPagerAdapter(
                this@CSFragment,
                CSListfragmnet
            )
        }
        viewPagerCs.offscreenPageLimit = 1

ViewAdapter가 초기화 되지않았다면 csCategory값들을 받아 map을 통해 데이터를 주입해준다. 여기서 CSListFragment가 나오는데 나중에 이 Fragment도 설명할테지만 이 부분에서 RecyclerView들을 생성해 adapter로 ViewPager2에 집어넣는 방식이다.

위의 코드들이 정상적으로 동작한다면

다음 이미지 처럼 데이터가 출력이 된다. 현재 이미지의 사진은 기능을 중심 구현을 위해 코드화 된 부분이라 조금 ui적으로 불안정한 부분이 있는데 위의 상단의 고객센터 부분과 하단의 Circle Button의 경우 CSFragment의 화면이고 중간의 이용방법 부분이 CSListFragment에서 RecyclerView를 받아와 ViewPager2 Adapter를 통해 집어넣은 부분이다.

이 부분에서의 문제점

ViewPager2의 경우 ViewGroup을 상속받아 RecyclerView를 생성할 수 있지만 원래의 ViewPager2의 목적에 적합하지 않다. 또한 기존의 속성에 따라 메모리에 좌우의 View를 생성했을 텐데 이것이 비효율적이라는 의견이 나왔다. 이렇게 개발되었던 것은 초반 생각했던 제작에서 변경된 것도 있었지만 그렇게 된다면 CS부분을 위한 별도의 RecyclerAdapter가 필요했기 때문이다.
기존에 사용되고 있던 코드들을 재사용하고 클래스들을 줄이기 위해 이런 방법으로 구현했지만 다른 팀원의 생각에는 이러한 부분이 오히려 더 비효율적일 수 도있다는 것이다. 그래서 저는 일단 ViewPager2의 메모리 부분에 대해 자료를 더 수집해 비교해 보고 별도의 Adapter를 통해 순수 RecyclerView를 생성할지 지금 방법을 고수할 지 고민해 볼 생각이다.

CSListFragment

다음은 CSFragment에 RecyclerView를 보내는 CSListFragment이다. 이 부분에서는 Adapter라는 변수에 데이터를 넣어 CSFragment에서 통합하는 것이다. CSListFragment는 임의로 값을 넣어놓은 데이터가 보여줘야하기때문에 CSListViewModel이라는 ViewModel이 존재하고 ViewModel을 받기 다음과 같이 ViewModel을 상속받아준다.

private val viewModel by viewModel<CSListViewModel> {
        parametersOf(csCategory)
    }
private val csCategory by lazy {
        arguments?.getSerializable(CS_CATEGORY_KEY) as CSCategory
    }

CSCategory라고 저장된 데이터를 받아오기 위해 parameter로 csCategory를 정의해주고 ViewModel에서 데이터를 받아온다.

또한 여기에는

private val resourcesProvider by inject<ResoucesProvider>()

ResourceProvider 라는 코드를 inject했는데 이는 CS 데이터에는 사용하지 않고 Home부분에 데이터를 출력할때 쓰이는 데이터Style이다. ModelRecyclerAdapter와 HomeListFragmentPagerAdapter를 같이 사용하기 위해 실제로는 사용하지 않지만 적용시킨 것이다.

다음은 RecycleView.adapter에 적용시킬 Adapter부분이다.

   private val adapter by lazy {
        ModelRecyclerAdapter<CSModel, CSListViewModel>(
            listOf(), viewModel, resourcesProvider,
            object : CSModelListener {
                override fun onClickItem(listModel: CSModel) {
                    val data = ImageData(listModel.csTitle, listModel.csContent, listModel.csAuthor)
                    val bundle = Bundle()
                    bundle.putParcelable("data", data)
                    view?.let { it1 ->
                        Navigation.findNavController(it1)
                  .navigate(R.id.action_CSFragment_to_CSDetailFragment, bundle)
                    }

Adapter에 적합한 Model과 ViewModel을 넣어주고 Listener를 만들어 해당 View부분을 클릭했을 때 동작할 Event를 넣어준다. 데이터를 클릭하면 해당하는 Mock데이터들을 Parcelable하고 Bundel에 담아 put시킨다. 그리고 Action을 할때 같이 담아서 CSDetailFragment로 같이 날려준다. CSDetailFragment에서는 그 데이터를 받아 다시 지정된 형식에 맞춰 데이터를 넣어준다.

ImageData

여기서 이미지 데이터는 직렬화 처리 방법을 통해 데이터의 전송속도를 높이고 시스템적인 부담이 적기 때문에 자주 사용된다.

코드를 보자면

@Parcelize
data class ImageData(
    val csTitle : String,
    val csContent : String,
    val csAuthor: String,
) : Parcelable

변수의 데이터의 타입을 String으로 지정해 주고 Parcelable를 상속받아준다.

EmailFragment

EmailFragment의 경우 고객센터에 질의 사항이 있을 때 소통하는 방법들 중 하나인 Email을 통해 연락을 취하는 것이다.

 private fun sendEmail() {
        val emaildata = EmailData(
            "gege2848@naver.com",
           binding.titleEdit.text.toString(),
            binding.contentEdit.text.toString())
        val intent = Intent(Intent.ACTION_SENDTO)
            .apply {
                type = "text/plain"
                data = Uri.parse("mailto:")
                putExtra(Intent.EXTRA_EMAIL, arrayOf(emaildata.emailAddress))
                putExtra(Intent.EXTRA_SUBJECT, emaildata.title )
                putExtra(Intent.EXTRA_TEXT,  emaildata.content  )
            }
        if (emaildata.title =="" || emaildata.title == null || emaildata.content == "" ||  emaildata.content  == null) {
            Toast.makeText(context, "제목 또는 내용을 입력해주세요", Toast.LENGTH_SHORT).show()
        }
        else {
            startActivity(Intent.createChooser(intent, "Send Email"))
            backStack()
        }
    }

일단 EmailData Parcelable에 전달될 이메일 address와 EditText들을 연결해준다 그 후
안드로이드 OS Mail시스템인 Gmail에게 EmailData를 Intent해준다. 각 위치에 맞게
SUBJECT(제목) , TEXT(내용) 보내준다. 동작 중 제목과 내용이 작성되지 않는다면 동작을 실행하지않고 제목 또는 내용을 작성해 달라는 Toast메시지를 출력하게 된다. 조건에 충족을 하게된다면 Intent를 실행한다. 여기서

backStack() 메서드는 Fragment가 백스택에 쌓여있기때문에 동작을 마치면 제거를 하여 이전의 화면을 돌아갈 수 있도록 작성을 하였다.

코드를 통해 구현한 Email이미지이다.

CSDetailFragment

해당 Fragment는 공지 글에 대한 내용과 같은 상세글들이 적힌 화면이다.

코드를 바로 본다면

      val csData = arguments?.getParcelable<ImageData>("data")
        title.text = csData?.csTitle.toString()
        author.text = csData?.csAuthor.toString()
        content.text = csData?.csContent.toString()

CSFragment에서 Bundle에 담아 보낸 데이터를 전달받아 데이터를 각각에 맞춰 데이터를 전달해준다. 데이터를 통해 해당 작성자나 제목 내용들을 사용자의 화면에 보여준다.

마치며

이로써 제가 작성한 부분에 대한 코드리뷰들을 설명하는 시간을 가져봤습니다. 다음의 글들로는 제가 작성을 하면서 생겼던 문제점들과 그 문제점들의 해결법 또한 의도치않게 해결된 문제에 대해서도 작성을 하도록 하겠습니다. 긴 글을 읽어주셔서 감사합니다.

profile
Android 개발 잘하고 싶어요!!!

0개의 댓글