mojo's Blog

Firebase - (2) 본문

카테고리 없음

Firebase - (2)

_mojo_ 2022. 3. 30. 14:39

Realtime Database 연동

 

1. Gradle Scripts => build.gradle(Module: ...) 에서 dependencies 부분에서 다음과 같이 코드를 추가해서 database 연동이 가능도록 설정한다. (추가 후 Sync Now 해주기)

 

 

2. 코틀린 파일 LikeActivity , 레이아웃 activity_like.xml , 그리고 manifests 에서 LikeActivity 를 추가해주도록 한다.

 

3. MainActivity.kt 에 화면이 시작하면 유저가 로그인했던 상태라면 activity_like 화면이 띄워지도록 하고 로그인하지 않은 상태면 activity_login 화면이 띄워지도록 한다.

 

 override fun onStart() {
    super.onStart()
    if (auth.currentUser == null){
        startActivity(Intent(this, LoginActivity::class.java))
    } else {
        startActivity(Intent(this, LikeActivity::class.java))
 	}
 }

 

4. LoginActivity.kt 에 회원가입을 하는 메서드와 로그인을 하는 메서드가 있다.

회원가입을 하는 메서드를 살펴보도록 하자.

private fun initSignUpButton() {
    val signUpButton = findViewById<Button>(R.id.signButton)
    signUpButton.setOnClickListener {
        val email = getInputEmail()
        val password = getInputPassword()

		auth.createUserWithEmailAndPassword(email, password)
            .addOnCompleteListener(this) {task->
                if(task.isSuccessful){
                    Toast.makeText(this, "회원가입에 성공했습니다", Toast.LENGTH_SHORT).show()
                } else{
                    Toast.makeText(this, "회원가입에 실패했습니다", Toast.LENGTH_SHORT).show()
                }
            }
    }
}

 

회원가입 버튼을 눌렀을 때 EditText 에 입력한 email, password 을 받아와서 db 를 생성한다.

이때 성공한 경우와 성공하지 못한 경우에 대해서 확인이 가능하다.

 

로그인을 하는 메서드를 살펴보도록 하자.

private fun initLoginButton() {
    val loginButton = findViewById<Button>(R.id.loginButton)
    loginButton.setOnClickListener {
        val email = getInputEmail()
        val password = getInputPassword()

		auth.signInWithEmailAndPassword(email, password)
            .addOnCompleteListener(this) { task ->
                if (task.isSuccessful) {
                    handleSuccessLogin()
                } else {
                    Toast.makeText(this, "로그인에 실패했습니다.", Toast.LENGTH_SHORT).show()
                }
            }
    }
}

 

로그인 버튼을 누르면 현재 DB에 있는 email, password 를 통해 로그인 여부를 확인할 수 있다.

이때 로그인된 경우에 handleSuccessLogin 메서드를 호출하여 MainActivity 로 이동한 후에 로그인 여부를 확인하여 다시 LikeActivity 로 이동하게 해준다.

 

handleSuccessLogin 메서드를 살펴보도록 하자.

private fun handleSuccessLogin() {
    if (auth.currentUser == null) {
        Toast.makeText(this, "로그인에 실패했습니다.", Toast.LENGTH_SHORT).show()
        return
    }

    val userId = auth.currentUser?.uid.orEmpty()
    val currentUserDB = Firebase.database.reference.child("Users").child(userId)
    val user = mutableMapOf<String, Any>()
    user["userId"] = userId
    currentUserDB.updateChildren(user)

	finish()
}

 

현재 로그인된 user의 이름이 null 일 경우에 예외 처리를 해줬다.

그리고 userId 를 "Users" 아래에 userId 를 채워준다.

즉, 아래와 같이 채워지는 형태임을 알 수 있다.

 

 

그리고 user["userId"] = userId 를 채워줌으로써 userId 내에 있는 "userId" 의 값을 현재 userId 을 넣어준 형태로 위와 같이 업데이트가 되면서 finish() 를 하게 된다.

finish() 를 하면 현재 로그인 창이 종료되며 MainActivity.kt 로 돌아가서 현재 로그인이 된 상태이므로 LikeActivity.kt 로 이동하게 된다.

 

5. LikeActivity.kt 코드를 살펴보도록 하자.

package com.example.dbpractice

import android.os.Bundle
import android.os.PersistableBundle
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.ValueEventListener
import com.google.firebase.database.ktx.database
import com.google.firebase.ktx.Firebase

class LikeActivity: AppCompatActivity() {

    private var auth: FirebaseAuth = FirebaseAuth.getInstance()
    private lateinit var userDB: DatabaseReference

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_like)

        userDB = Firebase.database.reference.child("Users")
        val currentUserDB = userDB.child(getCurrentUserId())
        currentUserDB.addListenerForSingleValueEvent(object : ValueEventListener{
            override fun onDataChange(snapshot: DataSnapshot) {
                if (snapshot.child("name").value == null){
                    showNameInputPopup()
                    return
                }

                // todo 유저정보 갱신
            }
            override fun onCancelled(error: DatabaseError) {
                TODO("Not yet implemented")
            }

        })
    }

    private fun showNameInputPopup() {
        val editText = EditText(this)

        AlertDialog.Builder(this)
            .setTitle("이름을 입력해주세요")
            .setView(editText)
            .setPositiveButton("저장"){ _, _ ->
                if (editText.text.isEmpty()) {
                    showNameInputPopup()
                } else {
                    saveUserName(editText.text.toString())
                }
            }
            .setCancelable(false)
            .show()

    }

    private fun saveUserName(name: String) {
        val userId = getCurrentUserId()
        val currentUserDB = Firebase.database.reference.child("Users").child(userId)
        val user = mutableMapOf<String, Any>()
        user["userId"] = userId
        user["name"] = name
        currentUserDB.updateChildren(user)
    }

    private fun getCurrentUserId(): String {
        if (auth.currentUser == null) {
            Toast.makeText(this, "로그인이 되어있지 않습니다", Toast.LENGTH_SHORT).show()
            finish()
        }

        return auth.currentUser?.uid.orEmpty()
    }
}

 

onCreate 메서드에서 userDB = ~~~ 부분은 현재 "Users" 에 대한 database 정보를 참조한다는 뜻으로 이해할 수 있다.즉, 아래와 같은 데이터들을 접근한다는 뜻으로 이해하면 좋을거 같다.

 

 

val currentUserDB = userDB.child(~~~) 부분에서  userDB 의 현재 유저가 접속한 ID 값에 대한 정보를 가져오는 것으로 이해할 수 있다.

예를 들어서  userId 가 JdPGRwE...s1 인 사용자의 DB 를 가져오게 된다면 currentUserDB 는 아래와 같은 데이터들을 접근하게 된다.

 

 

 

onDataChange 메서드는 현재 로그인한 사용자의 하단에 "name" 이라는 key 값이 존재하는지 안하는지를 살펴보며 없을 경우 showNameInputPopup() 메서드를 띄워서 dialog 를 띄우도록 하고 그렇지 않을 경우는 따로 구현하지 않았다.

 

showNameInputPopup() 메서드를 자세히 살펴보면 dialog 를 띄운 후에 editText 가 나타나게 된다.

그러면서 "저장" 버튼이 뜨면서 해당 버튼을 눌렀을 경우 editText 의 text 가 없을 경우 showNameInputPopup() 메서드를 다시 띄워서 dialog 가 다시 뜨도록 하게 하며 정상적으로 입력될 경우 입력한 name 값을 저장하도록 saveUserName() 메서드를 호출한다.

 

saveUserName() 메서드는 "name" 이라는 key 의 value 를 dialog 의 editText 에서 타이핑한 string 으로 넣어준 후에 database 를 udpate 한다.

mutableMapOf 이라는 key-value 를 저장하도록 하는 컬렉션을 이용하여 "userId", "name"의 key 값을 할당한 후에 해당하는 userId 의 정보를 update 한다.

 

실행해보면 다음과 같다.

 

그러나 실행했을 경우 이미 로그인된 상태라면 ?

 

 

위와 같은 화면이 뜨게 되는데, 회원가입 창 부터 다시 시작하고 싶을 경우 다음과 같이 해야 한다.

우선 앱을 삭제해야 하는데 아래와 같이 삭제가 가능하다.

 

 

그리고 다시 에뮬레이터를 실행하면 정상적으로 회원가입 창이 뜨게 된다.

 

 

그러면 회원가입을 하고 로그인 버튼을 눌러보도록 하자.

 

 

로그인 버튼을 누르면 아래와 같이 Realtime Database 가 update 되는 모습을 볼 수 있다. (+ 부분)

 

 

name 에 대한 value 가 없으므로 이를 추가해주도록 한다.

 

 

 

정상적으로 "name" 에 kakao 라는 value 가 들어가면서 업데이트 된 것을 볼 수 있다.

Comments