Firestore: 현재 위치와 시각 구해서 DB에 저장하기

3 분 소요


</br> 이제 DB를 읽는 건 했으니 쓰는 작업을 해 보자~~
프로젝트에서, 사용자가 고양이를 목격해 버튼을 누르면 작은 마커를 생성하고 DB에 현재 위치와 시각으로 목격 정보를 저장하는 함수를 만들었다.

FusedLocationProviderClient fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
  permissionCheck();
  return;
}
fusedLocationClient.getLastLocation()
  .addOnSuccessListener(this, new OnSuccessListener<Location>() {
    @Override
    public void onSuccess(Location location) {
      if( location != null ){
        double latitude = location.getLatitude();
        double longitude = location.getLongitude();
        Log.d("LOCATIONTEST", "위도: " + String.valueOf(latitude) + ", 경도: " + String.valueOf(longitude));

        Map<String, Object> data = new HashMap<>();
        data.put("name", selected);
        if( selected.equals("??") ){
            data.put("type", "white");
        }
        else{
            data.put("type", namesAndTypes.get(selected));
        }
        data.put("latitude", latitude);
        data.put("longitude", longitude);
        Date currentTime = Calendar.getInstance().getTime();
        String yyyyMM = new SimpleDateFormat("yyyyMM", Locale.getDefault()).format(currentTime);
        String dd = new SimpleDateFormat("dd", Locale.getDefault()).format(currentTime);
        String detectedTime = new SimpleDateFormat("HH:mm", Locale.getDefault()).format(currentTime);
        data.put("detectedTime", detectedTime);

        Map<String, Object> newDoc = new HashMap<>();
        newDoc.put("date", yyyyMM);
        mDatabase.document("catSmallMarkers/" + yyyyMM)
        .get()
        .addOnCompleteListener(task -> {
            if( task.isSuccessful() ){
                Map<String, Object>
                getDB = task.getResult().getData();
                if( getDB == null ){
                    Log.d("DB Error", "Error get DB no data", task.getException());
                    mDatabase.document("catSmallMarkers/" + yyyyMM)
                    .set(newDoc)
                    .addOnSuccessListener(documentReference -> Log.d("ADD","new Doc"))
                    .addOnFailureListener(e -> Log.d("ADD","Error adding: ",e));
                }
            }
            else{
                Log.d("SHOW", "Error show DB", task.getException());
            }
        });
        mDatabase.collection("catSmallMarkers/" + yyyyMM + "/" + dd)
        .add(data)
        .addOnSuccessListener(documentReference -> Log.d("ADD","Document added"))
        .addOnFailureListener(e -> Log.d("ADD","Error adding: ",e));
      }
    }
  });

DB에 고양이 이름, 타입과 현재 사용자의 위치와 시각으로 목격 정보를 저장하는 부분이다.

</br>

현재 위치 구하기

현재 위도와 경도를 구하기~~
처음에 구글맵 현재 위치, android GoogleMap current location 등 별의 별 검색어로 다 검색했지만 다 deprecated 함수라느니, 나오지 않았다…
mylocationbutton
https://developers.google.com/maps/documentation/android-sdk/location
자꾸 저 내 위치 레이어 추가해서 파란색으로 보여주는 거만 나옴…

알고 보니까 구글맵 기능을 안 쓰고 그냥 얻을 수 있었다! ㅋㅋ뻘짓함

FusedLocationProviderClient fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
  permissionCheck();
  return;
}
fusedLocationClient.getLastLocation()
  .addOnSuccessListener(this, new OnSuccessListener<Location>() {
    @Override
    public void onSuccess(Location location) {
      if( location != null ){
        double latitude = location.getLatitude();
        double longitude = location.getLongitude();
        Log.d("LOCATIONTEST", "위도: " + String.valueOf(latitude) + ", 경도: " + String.valueOf(longitude));
      }
    }
  });

물론 위치 정보를 얻어야 하니 퍼미션 체크는 반드시 해야 한다.
.getLastLocation()으로 마지막에 알려진 위치를 얻어 온다. gps를 켜고 있고 문제가 없다면 이게 현재 위치나 다름 없다.
</br>

현재 시각 구하기

Date currentTime = Calendar.getInstance().getTime();
String yyyyMM = new SimpleDateFormat("yyyyMM", Locale.getDefault()).format(currentTime);
String dd = new SimpleDateFormat("dd", Locale.getDefault()).format(currentTime);
String detectedTime = new SimpleDateFormat("HH:mm", Locale.getDefault()).format(currentTime);

자바의 SimpleDateFormat을 사용한다. 포맷에 맞게 입력만 해 주면 잘 나온다.

문자
y 연도
M 월(1~12)
d 일(1~31)
H 시(0~23)
h 시(1~12)
m 분(0~59)
s 초(0~59)

대충 잘 쓰이는 것들~~ 더 보려면 구글에 SimpleDateFormat 검색
</br>

DB에 쓰기

Map<String, Object> data = new HashMap<>();
// ***********
put some data
// ***********
mDatabase.collection(collectionPath)
.add(data)
.addOnSuccessListener(documentReference -> Log.d("ADD","Document added"))
.addOnFailureListener(e -> Log.d("ADD","Error adding: ",e));

Map<String, Object>에 데이터들을 넣고, 컬렉션 또는 문서를 그냥 추가해 주면 됨~~
문서를 추가하는 함수는 .add().set() 두 가지가 있다.

add()와 set()의 차이

간단함!! .set()은 문서의 ID를 사용자가 지정해서 문서를 추가할 때이고, .add()는 ID를 자동 생성해서 문서를 추가한다.
.add()는 문서의 ID를 별도로 지정할 필요가 없을 때 사용함.

// *********** 1
mDatabase.collection(collectionPath)
        .document(documentName)
        .set(data);

// *********** 2
mDatabase.document(collectionPath/documentName)
        .set(data);

// *********** 3
mDatabase.collection(collectionPath)
        .document()
        .set(data);

// *********** 4
mDatabase.collection(collectionPath)
        .add(data);

위 코드에서 1과 2가 같고, 3과 4가 같다.
1, 2는 collectionPath에 documentName이라는 ID의 문서를 추가한다.
3, 4는 collectionPath에 임의의 자동 생성된 ID의 문서를 추가한다.
</br>

주의할 점

1
예를 들어 내 프로젝트의 경우 작은 마커 정보들을 위와 같이 [ 연월 - 일 - 각 데이터가 담긴 문서들 ]로 구분할 필요가 있었다.
즉 [ 컬렉션 - 문서(연월) - 컬렉션(일) - 문서(데이터) ]의 중첩된 구조.

그렇다면

mDatabase.collection("catSmallMarkers/" + yyyyMM + "/" + dd)
.add(data);

이렇게 패스를 중첩해서 대충 새로 만들어 주면 잘 돌아갈까? 가 문제인데… 그냥 이러면 안 된다!!

이미 문서가 만들어진 상태에서 추가하는 건 상관없다. 그러나 예를 들어 7월의 1일, 컬렉션에 새로 ( 컬렉션/202107/01/정보 )를 넣는다면, 문서(연월, 202107)이 비어 있는 문서가 될 수 있기 때문…
2
위 사진은 ( temp/empty?/isEmpty?/a )로 컬렉션 temp에 바로 패스를 통해 a를 추가한 모습이다.
즉 컬렉션 temp에 empty?라는 문서는 없는데 바로 mDatabase.collection("temp/empty?/isEmpty?/a").set(data)로 a를 추가함.
이 문서에 데이터가 없다고 적혀 있는데, 실제로 돌려 보면 잘 안 돌아간다. 문서를 설명하는 데이터는 꼭 있어야 해서 그렇다는 것 같다.

Map<String, Object> newDoc = new HashMap<>();
newDoc.put("date", yyyyMM);
mDatabase.document("catSmallMarkers/" + yyyyMM)
.get()
.addOnCompleteListener(task -> {
    if( task.isSuccessful() ){
        Map<String, Object>
        getDB = task.getResult().getData();
        // catSmallMarkers 컬렉션에 yyyyMM라는 문서가 있는 지 확인한다.
        if( getDB == null ){  // 없으면 set으로 문서를 만든다.
            Log.d("DB Error", "Error get DB no data", task.getException());
            mDatabase.document("catSmallMarkers/" + yyyyMM)
            .set(newDoc)
            .addOnSuccessListener(documentReference -> Log.d("ADD","new Doc"))
            .addOnFailureListener(e -> Log.d("ADD","Error adding: ",e));
        }
    }
    else{
        Log.d("SHOW", "Error show DB", task.getException());
    }
});

// 이후 정상적으로 dd(날짜) 컬렉션에 data를 담은 문서 추가.
Map<String, Object> data = new HashMap<>();
// ***********
put some data
// ***********
mDatabase.collection("catSmallMarkers/" + yyyyMM + "/" + dd)
.add(data)
.addOnSuccessListener(documentReference -> Log.d("ADD","Document added"))
.addOnFailureListener(e -> Log.d("ADD","Error adding: ",e));

null 체크 한 번 해주는 거랑 비슷하다고 보면 될 듯~~

댓글남기기