

좌측 메뉴에서 Firestore Database 클릭

"데이터베이스 만들기" 버튼 클릭

위치는 Seoul로 맞추고 다음

테스트 모드로 맞추고 만들기
테스트 모드는 한달동안 접속이 가능하다


컬렉션 : 테이블
문서 : 행 (문서 ID는 자동ID 기능이 있다)
필드 : 변수
컬렉션에 접근해서 특정 필드의 값이 ~~인 문서를 찾는 방식
컬렉션 시작 버튼 클릭

컬렉션 ID 입력 후 다음
문서ID는 자동ID로 만든 후 필드와 유형,값 입력


문서 추가

모듈 수준의 build.gradle.kts에서 dependencies에 firestore 2개 추가
dependencies {
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
implementation("androidx.core:core-splashscreen:1.0.1")
implementation(platform("com.google.firebase:firebase-bom:32.7.4"))
implementation("com.google.firebase:firebase-analytics")
implementation("com.google.firebase:firebase-firestore:24.10.3")
}
컬렉션에 접근
val collection = Firebase.firesotre.collection("c1")
컬렉션 내에 있는 모든 문서를 가져오기
// 컬렉션 내에 있는 모든 문서를 가져오기
collection.get().addOnSuccessListener {
// 가져온 문서의 수 만큼 반복
it?.documents?.forEach {
// 문서로부터 필드값을 가지고와서 출력
val f1 = it?.getString("f1")
val f2 = it?.getLong("f2")
Log.d("test1234", "f1 : $f1")
Log.d("test1234", "f2 : $f2")
}
}

조건절을 사용하려면
whereEqualTo메서드를 사용하면 된다.
collection.whereEqualTo("f2",100).get().addOnSuccessListener {

이러한 리스너 방식은 심각한 문제가 있는데
그것이 콜백지옥이다.
리스너 안에 리스너가 포함되고 또 그안에 리스너가 포함되는 연속적인 구조
A.get().addOnSuccessListener{
B.get().addOnSuccessListener{
C.get().addOnSuccessListener{
...
}
}
}
통신을 하여 데이터를 가져오는데 시간이 걸리기때문에 A.get(),B.get(),C.get()을 순서대로 나열해서 실행을 해도 그 순서가 보장받지 못한다.
A,B,C~ 순차적으로 실행하기 위해서는 위와 같이 리스너를 사용해 콜백지옥 구조를 구현할 수 밖에 없다.
하지만 코틀린에서는 코루틴을 지원하고 있어 이러한 콜백지옥을 피하기위해 코루틴을 사용해 동기화 처리하면 가독성 좋게 순서대로 코드를 짤 수 있게 된다.
아래와 같은 함수가 있을 때
fun fsTest():Long{
var result = 0L
// 컬렉션에 접근한다.
val collection = Firebase.firestore.collection("c1")
// 컬력션내에 있는 모든 문서를 가져온다.
collection.get().addOnSuccessListener {
// 가져온 문서의 수 만큼 반복한다.
it?.documents?.forEach {
// 문서로 부터 필드값을 가지고와서 출력한다.
val f1 = it?.getString("f1")
val f2 = it?.getLong("f2")
result += f2!!
Log.d("test1234", "f1 : $f1")
Log.d("test1234", "f2 : $f2")
}
}
return result
}
코루틴을 사용하여 아래와 같이 코드를 바꾸면
CoroutineScope(Dispatchers.Main).launch {
val result = fsTest()
Log.d("test1234","result:$result")
}
suspend fun fsTest():Long{
var result = 0L
// 컬렉션에 접근한다.
val collection = Firebase.firestore.collection("c1")
val job1 = CoroutineScope(Dispatchers.IO).launch {
// 컬렉션에 접근하여 모든 문서를 가져온다.
// 코루틴 내부에서 await을 사용하면 작업이 완료될때 까지 대기했다가
// 작업이 완료되면 값을 반환 받을 수 있다.
val data = collection.get().await()
// 가져온 문서의 수 만큼 반복한다.
data.documents.forEach {
// 문서로 부터 필드값을 가지고와서 출력한다.
val f1 = it?.getString("f1")
val f2 = it?.getLong("f2")
result += f2!!
Log.d("test1234", "f1 : $f1")
Log.d("test1234", "f2 : $f2")
}
}
job1.join()
return result
}
코루틴을 사용하게 되면 함수 내부의 코드와 코루틴스코프 내부의 코드가 별개로 동작하기 때문에 코루틴스코프 내부의 코드를 기다릴 수 있도록 join()메서드를 호출해줘야 한다.
코루틴을 사용하지 않는다면 리스너를 등록해야하고, 코루틴을 사용하려면 join으로 코루틴 수행 대기를 시켜야 한다.
join으로 대기를 시키지 않는경우 코루틴스코프의 코드가 끝나기전에 이미 함수 내부 코드가 끝나버려서 0값을 리턴시키게되므로 아래와 같은 결과가 나온다.

하지만 join으로 함수 내부의 코드 수행을 대기 시켜 코루틴 스코프가 끝날때까지 기다리면 아래와 같이 정상적으로 기대한 결과값을 받을 수 있다.

판매자 화면
구매자 화면
서비스를 따로따로 구분해서만들어야함