MVP 을 통해 Firebase Realtime Database을 구현해 보자

Assist·2023년 7월 19일
0

Design Pattern

목록 보기
5/7

MVP 패턴이란?

Model View Presenter 패턴을 줄여 말해 MVP 패턴이라고 합니다.

MVC 패턴에서 Model 와 View의 의존성이 높아 유지보수가 어렵다는 단점을 보완하여 만든것이 MVP 패턴입니다.

아래에 이해를 돕기 위해 이미지를 첨부하겠습니다.

구현 시작

일단 시작전 전 Android 앱 개발자 임으로 아래를 사용했습니다.

  • Firebase Real Time Database
  • language : Kotlin
  • IDE : Android Studio

이정도 입니다. 그럼 가봅시다

사용 라이브러리

    // Log
    implementation 'com.jakewharton.timber:timber:5.0.1'

    //Layout
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'

    //Firebase
    implementation(platform("com.google.firebase:firebase-bom:32.2.0"))
    implementation("com.google.firebase:firebase-analytics-ktx")
    implementation("com.google.firebase:firebase-crashlytics-ktx")
    implementation("com.google.firebase:firebase-database-ktx")

위에서 부터 설명하자면

  • Timber : Logcat 을 쉽게 보기 위한 라이브러리
  • Layout : 주로 동적 Layout을 사용하기 위해 ContranitLayout을 사용했습니다.
  • Firebase : database 은 Realtime Database 을 사용하기 위해 선언했습니다.
    crashlytics 은 앱이 사망했을때 앱 로그를 저장하기 위해 선언했습니다.

Contrat

Contract라는 클래스를 선언해 해당 이벤트가 끝났을때 데이터를 view로 넘겨주기 위하여 interface으로 만들어 클래스를 만들엇습니다.

interface Contract {

    interface View{
        fun showSignUpResult(message:  String)
        fun showLoading()
    }

    interface Presenter{
        fun requestSignUp(userData : UserInfo)
    }


}
  • showSignUpResult 을 통해 결과값을 return 해주기 위해 선언했습니다.
  • showLoading 은 Firebase 을 통해 data 조회 할때 시간이 걸리니 Loading을 한 창을 올리기 위해 만들었습니다.

View

class SignUpActivity : AppCompatActivity()  , Contract.View{

    private var _binding : ActivitySignUpBinding ?= null
    private val binding get() = _binding!!

    private lateinit var presenter : SignUpPresenter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        _binding = ActivitySignUpBinding.inflate(layoutInflater)
        setContentView(binding.root)
        init()
        addListener()
    }

    private fun init(){
        presenter = SignUpPresenter(this)
    }
    private fun addListener(){

        binding.btnSignUp.setOnClickListener {
            val id = binding.editId.text.toString().replace(" ","")
            val password = binding.editPassword.text.toString().replace(" ","")
            val phoneNumber = binding.editPhoneNumber.text.toString().replace(" ","")
            val nickName  = binding.editNickName.text.toString().replace(" ","")

            if(id == "" || password == "" || phoneNumber == "" || nickName == ""){
                Toast.makeText(this , getString(R.string.msg_input_data) , Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }
            val data = UserInfo(id , password , phoneNumber , nickName)
            presenter.requestAlreadySignUp(data)

        }
    }

    override fun onDestroy() {
        super.onDestroy()
        _binding = null
    }

    override fun showSignUpResult(message: String) {
        Timber.d("The data is Come")
    }

    override fun showLoading() {
        Timber.d("Loading for signUp")
    }
}

interface 에 View 을 implement 해서 function 을 override 을 해서 사용합니다 .

그후 Init 에서 presenter = SignUpPresenter(this) 을 해 Presenter 을 사용합니다.

Presenter

class SignUpPresenter(private val view : Contract.View) : FirebaseDataListener , Contract.Presenter{

    private val dataManager: FirebaseDataManger = FirebaseDataManger()

    fun requestAlreadySignUp(data : UserInfo){
        view.showLoading()
        dataManager.readUserInfo(data.phoneNumber , this )
    }
    override fun onMessageIsCome(data: UserInfo) {
        Timber.d("Success to get UserInfo $data")

    }

    override fun onMessageIsFail(message: String) {
        Timber.d("Success to get UserInfo $message")
    }

    override fun requestSignUp(userData: UserInfo) {
         //아직 미구현
    }

}
  • fun requestAlreadySignUp
    이 함수는 이미 회원이 가입했는지 체크하기 위해 만들었습니다.
interface FirebaseDataListener {

    fun onMessageIsCome(data: UserInfo)
    fun onMessageIsFail(message: String)

}

Model

Model(Firebase database 조회) 하기 전에 해당 데이터는 비동기 적으로 오기 떄문에 데이터가 오면 Listner 을 하기 위해 선언했습니다.

class FirebaseDataManger {
    private var database = Firebase.database(BuildConfig.FIREBASE_DATABASE_URL)

    fun readUserInfo(phoneNumber : String , listener : FirebaseDataListener){
        val url = BuildConfig.userInfo+"/"+phoneNumber
        database.getReference(url).addListenerForSingleValueEvent(object: ValueEventListener{
            override fun onDataChange(snapshot: DataSnapshot) {
                val value = snapshot.getValue<UserInfo>()
                if(value == null){
                    listener.onMessageIsFail("error to get Message")
                    return
                }
                listener.onMessageIsCome(value)
                Timber.d("Success to get Firebase Database $value")
            }

            override fun onCancelled(error: DatabaseError) {
                Timber.d("Fail to get Firebase Database")
                listener.onMessageIsFail(error.message)
            }
        })
    }
}

그후 Firebase에서 데이터를 가져오는 것 구현합니다.
참고로 Firebase Realtime database 은 url에 / 가 꼭 붙어야 합니다. 안붙으면 아무것도 안옵니다.

예를들어 runningProject/realtimeDatabase/userInfo 해야 데이터를 Return 합니다.

그후 인자로 받은 listener 을 통해 메세지를 return 해줍니다.

그럼 다시 Presneter 로 가보겠습니다.

class SignUpPresenter(private val view : Contract.View) : FirebaseDataListener , Contract.Presenter{

    private val dataManager: FirebaseDataManger = FirebaseDataManger()

    fun requestAlreadySignUp(data : UserInfo){
        view.showLoading()
        dataManager.readUserInfo(data.phoneNumber , this )
    }
    override fun onMessageIsCome(data: UserInfo) {
        Timber.d("Success to get UserInfo $data")

    }

    override fun onMessageIsFail(message: String) {
        Timber.d("Success to get UserInfo $message")
    }

    override fun requestSignUp(userData: UserInfo) {
         //아직 미구현
    }

}

그후 onMessage을 통해 해당 값을 return 받을수 있겠지요

그후 인자로 받은 view을 통해 호출하면 view에 해당 값을 reutrn 해줄수 있습니다.

그럼 오늘도 읽어주셔서 감사합니다

-피드백와 비판은 언제나 환영입니다-

profile
안드로이드만 좋아하는 특이한 개발자

0개의 댓글