ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 간단한 MVVM 패턴 예제
    안드로이드 학습/Android 기술면접 대비 코드 2023. 6. 7. 21:23

    기본적으로 MVC나 MVP 패턴 같은 의존성을 없애기 위해 Databinding을 적용 시켰고 LiveData도 적용시켰습니다.

     

    삼국지 영웅 뽑기를 주제로 선정!

     

    1.build.gradle

    android {
     
    	... 생략 ...
        
        buildFeatures {
            dataBinding = true
        }
    }
    • 먼저 build.gradle 파일에 dataBinding을 사용하겠다는 선언 추가

     

    2. Character.kt

    data class Character(var name: String, var strength: Int, var intelligence: Int)
    • 삼국지 인물의 이름, 무력, 지력을 넣은 data class.  
    • 'data class' 로 지정해주면 알아서  getter setter method 지원!!!

     

    3. Model.kt

    class Model {
    
        private val characterList = mutableListOf<Character>()
        private lateinit var character: Character
    
        init {
            fillCharacter()
        }
    
        private fun fillCharacter() {
            characterList.add(Character("유비", 80, 80))
            characterList.add(Character("조조", 85, 95))
            characterList.add(Character("손권", 70, 75))
            characterList.add(Character("제갈량", 30, 100))
            characterList.add(Character("여포", 100, 30))
        }
    
        fun getRandomCharacter(): Character {
            character = characterList[(Math.random() * 5).toInt()]
            return character
        }
    
    }
    • fillCharacter에서 5명의 인물만 미리 넣어놓음
    • getRandomCharacter는 랜덤하게 5명의 인물중 하나만 선택할 예정. ViewModel에서 사용될 예정.

     

    4. ViewModel.kt

    class MainViewModel : ViewModel() {
    
        private var model: Model = Model()
        private var _character = MutableLiveData<Character>()
        val character: LiveData<Character>
            get() = _character
    
        fun getRandomCharacter() {
            _character.value = model.getRandomCharacter()
        }
    
        fun isShow(str: String?): Boolean {
            return str != null && str != "0"
        }
    }
    • getRandomCharacter()는 model에서 랜덤하게 인물을 정하는 부분 가져옴
    • isShow는 xml파일에서 visible을 세팅하기 위해 만들어준 부분. 왜냐하면 맨 처음에는 정보가 없으면 TextView가 안보여지게 하려고 Visible 세팅

     

    5. MainActivity.kt

    class MainActivity : AppCompatActivity() {
    
        lateinit var binding: ActivityMainBinding
        var mainViewModel = MainViewModel()
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    
            binding.apply {
                // **중요** binding에 LifeCycleOwner을 지정해줘야 LiveData가 실시간으로 변화
                lifecycleOwner = this@MainActivity
    
                // xml 파일에 선언한 viewModel
                viewModel = mainViewModel
            }
        }
    
        fun getRandomCharacter() {
            mainViewModel.getRandomCharacter()
    
        }
    
    }

     

    • 데이터 바인딩을 사용하기 위해 아래 2줄 추가
    lateinit var binding: ActivityMainBinding
    binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
    • 실시간 데이터 변화를 위해 'lifecycleOwner'와 'viewModel' 지정
    • 'viewModel' 같은 경우 xml에서 variable로 지정될 것을 연결 시켜주는 것이다.
    binding.apply {
       // **중요** binding에 LifeCycleOwner을 지정해줘야 LiveData가 실시간으로 변화
       lifecycleOwner = this@MainActivity
    
       // xml 파일에 선언한 viewModel
       viewModel = mainViewModel
    }

     

    6. activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <data>
    
            <import type="android.view.View" />
    
            <variable
                name="viewModel"
                type="w2022v9o12.simple.simplemvvm.viewmodel.MainViewModel" />
    
        </data>
    
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <LinearLayout
                android:id="@+id/characterInfoLayout"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_marginBottom="100dp"
                android:gravity="center"
                android:orientation="vertical"
                app:layout_constraintBottom_toTopOf="@+id/plusBtn"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent">
    
                <TextView
                    android:id="@+id/charName"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@{viewModel.character.name!=null ? `이름 : ` + viewModel.character.name : `영웅을 뽑아주세요.`}"
                    android:textColor="@color/black"
                    android:textSize="20dp"/>
    
                <TextView
                    android:id="@+id/strength"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="10dp"
                    android:text="@{`무력 :` + String.valueOf(viewModel.character.strength), default=``}"
                    android:textColor="@color/black"
                    android:textSize="20dp"
                    android:visibility="@{viewModel.isShow(String.valueOf(viewModel.character.strength)) ? View.VISIBLE : View.GONE , default=gone}" />
    
                <TextView
                    android:id="@+id/intelligence"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="10dp"
                    android:text="@{`지력 :` + String.valueOf(viewModel.character.intelligence), default=``}"
                    android:textColor="@color/black"
                    android:textSize="20dp"
                    android:visibility="@{viewModel.isShow(String.valueOf(viewModel.character.intelligence)) ? View.VISIBLE : View.GONE , default=gone}" />
            </LinearLayout>
    
            <Button
                android:id="@+id/plusBtn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="150dp"
                android:onClick="@{() -> viewModel.getRandomCharacter()}"
                android:text="삼국지 영웅 뽑기"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent" />
    
        </androidx.constraintlayout.widget.ConstraintLayout>
    </layout>

     

    • databinding을 위해 layout 태그로 감싸기
    • View.VISIBLE을 사용하기 위해 임포트
    <import type="android.view.View" />
    • 만들어진 viewModel을 xml에 가져오기
    <variable
        name="viewModel"
        type="w2022v9o12.simple.simplemvvm.viewmodel.MainViewModel" />
    • textview에 Visible을 적용시키기 위해 조건부 연산자(? : )를 사용
    • viewModel에서 만든 'getRandomCharacter()'와 button 연동
    android:onClick="@{() -> viewModel.getRandomCharacter()}"

     

    최종 결과 보기 :

     

     

     

    간단히 mvvm + databinding + livedata 예제를 만들어 보았다.

     

    데이터 바인딩과  livedata를 공부하긴 했었지만 예제를 만들어 본것이 아니어서 한참 헤맸다.

     

    이참에 그냥 databinding과 livedata도 예제로 따로 만들어 보아야겠다.

Designed by Tistory.