[AndroidStudio, FireBase, SpringBoot] KnockKnock 개발일지 -0424 (인근 유저에게 메세지 전송)

Hyebin Lee·2022년 4월 24일
0

knockknock 개발일지

목록 보기
28/29
post-thumbnail

참고한 링크

[Spring Boot] Firebase 연동 방법.
spring boot - 파이어베이스 realtime database 연결
Firebase Realtime Database 조금 더 자세히
지역쿼리
Android에서 데이터 읽기 및 쓰기

오늘의 이슈

Q. firebase에서 모든 멤버의 location을 다 가져온 뒤 spingboot에서 각 멤버와 targetlocation의 거리를 일괄로 전부 계산할 것인지, firebase에서 미리 계산한 뒤 인근 user의 id만 보내줄 것인지?
-> 이 문제는 바보같이 생각했다.. 애초에 Springboot랑 firebase를 연동할 필요가 없었다. 어차피 firebase는 서버리스이기 때문에 안드로이드에서 유저가 인근 유저들에게 메세지를 전송할 때, 안드로이드 단에서 firebase 쿼리문으로 인근 유저들을 전부 가져오면 된다. 그리고 그 인근 유저들에게 메세지를 보내겠다고 안드로이드에서 서버로 메세지 전송 api 만 보내주면 되는것..

AndroidStudio에서 Geohash로 firebase 쿼리 짜기

Geohash는 위치 기반 서비스에서 쿼리가 복잡하기 때문에 해당 쿼리를 간단한 코드만으로 사용할 수 있도록 한다.

1. Geohash implementation

// Add this to your app/build.gradle
implementation 'com.firebase:geofire-android-common:3.1.0'

2. 기존 firebase에 유저 위치 업데이트 코드 Geohash로 수정하기

Geohash를 사용하여 쿼리를 쓰기 위해서는 real time db에 저장된 데이터 자체가 Geohash 형태로 저장이 되어있어야 한다. 따라서 그에 맞게 기존 코드를 수정해주었다.

  • firebase에 업데이트 할 필드 수정
@IgnoreExtraProperties
public class UserLocation {

    private String id;
    private double latitude;
    private double longitude;
    private String geohash; //📌추가 

    protected UserLocation(){}

    public Double getLatitude() {
        return latitude;
    }

    public void setLatitude(Double latitude) {
        this.latitude = latitude;
    }

    public Double getLongitude() {
        return longitude;
    }

    public void setLongitude(Double longitude) {
        this.longitude = longitude;
    }

    public UserLocation(String id, Double latitude, Double longitude) {
        this.id = id;
        this.latitude = latitude;
        this.longitude = longitude;
        this.geohash = GeoFireUtils.getGeoHashForLocation(new GeoLocation(latitude, longitude)); //📌추가 
    }
}

3. GeoQuery 코드짜기

package org.techtown.knockknock.location;

import android.util.Log;

import androidx.annotation.NonNull;

import com.firebase.geofire.GeoFireUtils;
import com.firebase.geofire.GeoLocation;
import com.firebase.geofire.GeoQueryBounds;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.Query;
import com.google.firebase.firestore.QuerySnapshot;

import java.util.ArrayList;
import java.util.List;

public class GeoQuery {

    private static FirebaseFirestore db = FirebaseFirestore.getInstance();
    private static List<String> userId = new ArrayList<>();

    public static List<String> findUserIdsNear(double targetlatitude, double targetlongitude){
        final GeoLocation target = new GeoLocation(targetlatitude,targetlongitude);
        final double radiusInM = 1*1000; // 1km 로 범위 설정

        List<GeoQueryBounds> bounds = GeoFireUtils.getGeoHashQueryBounds(target,radiusInM);
        List<Task<QuerySnapshot>> tasks = new ArrayList<>();
        for(GeoQueryBounds b: bounds){
            Query q = db.collection("userlocation")
                    .orderBy("geohash")
                    .startAt(b.startHash)
                    .endAt(b.endHash);
            tasks.add(q.get());
        }
        Tasks.whenAllComplete(tasks)
                .addOnCompleteListener(new OnCompleteListener<List<Task<?>>>() {
                    @Override
                    public void onComplete(@NonNull Task<List<Task<?>>> t) {
                        List<DocumentSnapshot> matchingDocs = new ArrayList<>();
                        for(Task<QuerySnapshot> task: tasks){
                            QuerySnapshot snap = task.getResult();
                            for(DocumentSnapshot doc: snap.getDocuments()){
                                double lat = doc.getDouble("lat");
                                double lng = doc.getDouble("lng");

                                GeoLocation docLocation = new GeoLocation(lat,lng);
                                double distanceInM = GeoFireUtils.getDistanceBetween(docLocation,target);
                                if(distanceInM<=radiusInM){
                                    matchingDocs.add(doc);
                                    userId.add(doc.getId());
                                }
                            }
                        }
                    }
                });
        for(String id: userId){
            Log.d("GeoQuery","target 위치 인근 유저 아이디: "+id);
        }
        return userId;
    }
}

0개의 댓글