Firestore, GoogleMap: DB에서 읽어서 구글맵에 마커 만들기
</br>
프로젝트에서 만든 함수다. DB에 저장된 고양이 정보를 읽어 구글맵에 보여 준다.
</br>
저장된 DB 형태는 이런 식이다.
catMarkers 컬렉션에 각 고양이 별로 문서가 있다. 문서의 필드에 위도, 경도, 이름, 타입이 있다.
위도와 경도로 구글맵 마커를 위치시키고, 각 마커마다 이름을 title에 달아 주며, 타입에 따라 마커의 이미지가 달라진다.
/*
DB에서 정보 들고 와서 마커 보여주기
*/
public void setMarkersFromDB() {
Log.d("Marker", "set marker");
mDatabase.collection("catMarkers")
.get()
.addOnCompleteListener(task -> {
if( task.isSuccessful() ){
Log.d("Marker", "Successful");
String catName = "?";
String type = "?";
double latitude = 0.0;
double longitude = 0.0;
for(QueryDocumentSnapshot document : task.getResult()){
Map<String, Object> getDB = document.getData();
Object ob;
if( (ob = getDB.get("name")) != null ){
catName = ob.toString();
if( !(catNames.contains(catName)) ){
catNames.add(catName);
}
}
if( (ob = getDB.get("type")) != null ){
type = ob.toString();
namesAndTypes.put(catName, type);
}
if( (ob = getDB.get("latitude")) != null ){
latitude = Double.parseDouble(ob.toString());
}
if( (ob = getDB.get("longitude")) != null ){
longitude = Double.parseDouble(ob.toString());
}
Log.d("Marker Info", catName + " " + type);
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(new LatLng(latitude, longitude))
.title(catName)
.snippet("반가워요")
.icon(BitmapDescriptorFactory.fromResource(getResources().getIdentifier(type,"drawable",getPackageName())));
mMap.addMarker(markerOptions);
}
}
else{
Log.d("Marker", "Error show DB", task.getException());
}
});
} // End setMarkersFromDB();
전체 함수 코드다.
</br>
DB 읽기
우선
FirebaseFirestore mDatabase = FirebaseFirestore.getInstance();
이 코드로 mDatabase를 미리 초기화 해 줘야 한다.
// DB에서 컬렉션 읽기
mDatabase.collection(collectionPath)
.get()
.addOnCompleteListener(task -> {
if( task.isSuccessful() ){
for(QueryDocumentSnapshot document : task.getResult()){
Map<String, Object> getDB = document.getData();
if( getDB == null ){
// do something
}
}
}
else{
Log.d("Error", "Error show DB", task.getException());
}
});
구글맵 부분은 빼고 기본만 들고 왔다.
mDatabase.collection(collectionPath)
로 컬렉션에 접근할 수 있다.
.get()
으로 데이터를 읽고, .addOnCompleteListener()
에서 데이터가 다 로드되면 할 일을 하면 된다.
만약 성공적으로 읽었다면, for(QueryDocumentSnapshot document : task.getResult())
으로 컬렉션 안의 모든 문서들을 document로 받아 for문을 돌려 다룰 수 있다. 이 때 읽어 온 데이터는 Map<String, Object>
형식이다.
// DB에서 문서 읽기
mDatabase.document(documentPath))
.get()
.addOnCompleteListener(task -> {
if( task.isSuccessful() ){
Map<String, Object> getDB = task.getResult().getData();
if( getDB == null ){
// do something
}
}
else{
Log.d("Error", "Error show DB", task.getException());
}
});
비슷하게 DB에서 문서를 읽을 때다.
문서의 필드에 데이터가 있으므로, 컬렉션을 읽을 경우 컬렉션 안의 모든 문서들의 필드를 조회하기 위해 for(QueryDocumentSnapshot document : task.getResult())
으로 문서들을 하나 하나 확인하지만, 그냥 문서를 읽을 때는 바로 task.getResult().getData()
로 DB를 읽을 수 있다.
</br>
구글맵에 마커 만들기
for(QueryDocumentSnapshot document : task.getResult()) {
Map<String, Object> getDB = document.getData();
Object ob;
if( (ob = getDB.get("name")) != null ){
catName = ob.toString();
if( !(catNames.contains(catName)) ){
catNames.add(catName);
}
}
if( (ob = getDB.get("type")) != null ){
type = ob.toString();
namesAndTypes.put(catName, type);
}
if( (ob = getDB.get("latitude")) != null ){
latitude = Double.parseDouble(ob.toString());
}
if( (ob = getDB.get("longitude")) != null ){
longitude = Double.parseDouble(ob.toString());
}
// null 체크를 해 주면 더 안전하다. 안 했는데 혹시 값이 없으면 앱 멈출 수 있음...
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(new LatLng(latitude, longitude))
.title(catName)
.snippet("반가워요")
.icon(BitmapDescriptorFactory.fromResource(getResources().getIdentifier(type,"drawable",getPackageName())));
mMap.addMarker(markerOptions);
}
마커 만드는 부분은 아래 7줄이다.
MarkerOptions markerOptions = new MarkerOptions();
로 마커를 만들기 위한 정보들을 저장할 마커 옵션 객체를 만든다. .position(new LatLng(latitude, longitude))
으로 위도와 경도로 마커를 만들 수 있다. 이까지만 해도 기본적인 마커는 만들어진다.
.title()
은 타이틀, 위 사진에서 봤듯이 위의 굵은 글씨고 .snippet()
은 아래의 작은 글씨다.
.icon()
으로 아이콘을 설정할 수 있다.
BitmapDescriptorFactory.fromResource(getResources().getIdentifier(type,"drawable",getPackageName()))
를 나눠서 보면
getResources().getIdentifier(type,"drawable",getPackageName())
로 type
이라는 이름의 파일을 리소스에서 찾아서 얻고,
BitmapDescriptorFactory.fromResource()
로 해당 리소스로 비트맵 디스크립터를 만들어 넘겨준다.
마지막으로 mMap.addMarker(markerOptions);
로 맵에 마커를 추가할 수 있다.
</br>
주의할 점
public void someFunction() {
int a = 0, b = 0;
mDatabase.collection(collectionPath)
.get()
.addOnCompleteListener(task -> {
if( task.isSuccessful() ){
for(QueryDocumentSnapshot document : task.getResult()){
Map<String, Object> getDB = document.getData();
if( getDB == null ){
// *********** 2
read and set a = 10, b = 10;
// ***********
// *********** 3
print a + b
// ***********
}
}
}
else{
Log.d("Error", "Error show DB", task.getException());
}
});
// *********** 1
print a + b
// ***********
}
혹시 실수할 수 있는 부분인데~ 위에서 출력 결과는 0, 20이다.
DB에서 값을 읽는 데에 시간이 걸리기 때문이다. 비동기식으로 DB에서 읽어 올 동안 다른 일을 할 수 있게 하기 때문에, 표시한 바와 같이 가장 아래의 프린트문이 먼저 실행되고 그 다음 DB에서 값을 읽고 설정하고 프린트하게 될 것이다.
따라서 .addOnCompleteListener()
에서 읽기가 complete 됐을 때에 처리를 해야 한다~~
댓글남기기