Firebase는 여러 막강한 기능들을 제공하고 있습니다.
너무도 막강해서 마치 마법같이 느껴지고
이러한 기능을 제공하는 구글에 감탄하게 됩니다.
그 첫 번째 감동으로 Realtime Database에 대해 간단히 소개합니다.
Firebase Realtime Database를 간단히 소개하자면
Cloud Database라고 할 수 있습니다.
Cloud Database이기 때문에 플랫폼 종속성이 없습니다.
실제 Firebase의 다른 모든 기능들이 Android, IOS, Web, Server 플랫폼에서 자유롭게 사용 가능하죠.
그럼 Cloud이기 때문에 온라인이 아닌 상황(인터넷 접속이 안되는 상황)에서는 사용이 불가하냐?
그것도 아닙니다.
데이터를 디스크에 유지하므로 오프라인일 때에도 문제없이 사용가능합니다.
이후 네트워크에 연결되면 데이터를 자동으로 동기화시켜주기 때문에 네트워크에 대한 걱정은 접으시기 바랍니다.
개인적으로 저 역시 Android/Firebase를 이제 입문하여 학습/적용하는 단계이기 때문에
자세한 내용은 알지 못합니다만
한가지 의문점이 생깁니다.
과연 SQLite를 사용한 내부 데이터 저장소를 앞으로도 사용할 필요가 있을까?
특히나 요즘 같이
빵빵한 네트워크 환경,
고성능의 디바이스,
무엇보다 빅데이터 분석을 통한 차별화된 서비스 제공
등을 고려하면 서버로의 데이터 취합은 필수로 보입니다.
그리고 빠른 트렌드 변화에 유연하게 대응하기 위해서는 실제 물리 서버 구축보다는 Cloud를 이용하는 것이 강점이 될 것이고요.
그런 점에서 구글에서 제공하는 Firebase Realtime Database는 개발자들에게 큰 무기가 되지 않나 싶습니다.
다만 한가지 염두에 두어야 할 점은 Realtime Database는 익히 알고 있는 관계형 데이터베이스(RDBMS)는 아니라는 것입니다.
Realtime Database에서는 데이터들이 아래와 같이 json 형식으로 저장되기 때문에
관계형 데이터베이스와는 다른 데이터 구조를 생각해야 합니다.
성능과 데이터 중복, 그리고 트랜잭션 관리 등 생각해야할 요소들이 좀 있을 것 같습니다.
이런 자세한 이야기는 우선 나중으로 미루고,
당장 그럼 어떻게 데이터를 쓰고/읽고/수정하고/삭제하는지.
기본적인 CRUD에 대해 소개하겠습니다.
그 구현 난이도에 따라 다음 순서로 이야기를 시작하도록 하겠습니다.
본 포스팅은 Google Firebase 공식 문서를 참조하여 작성되었습니다.
https://firebase.google.com/docs/database/android/start/
그 첫 단계로 Android Project에 환경 구축하는 방법에 대해 소개합니다.
app 수준의 build.gradle에 아래와 같이 firebase database를 추가합니다.
실제 Firebase Realtime Database에 저장된 데이터들은 다음과 같습니다.
최상위 mandal-art 데이터베이스 안에 mandalarts, plans, users 와 같이 3개의 항목이 존재하고
users 안에 제 이메일 주소를 베이스로한 데이터가 저장되어 있습니다.
(저는 개인적으로 이 mandalarts, plans, users를 각각의 테이블로 이해를 하고 접근을 하였습니다.)
위 코드는 해당 프로젝트의 데이터베이스에서 users 영역에 대한 DatabaseReference를 얻는 코드라고 보면 됩니다.
개발자는 이 DatabaseReference (myRef)를 통해 CRUD 작업을 진행할 수 있습니다.
위에서 얻은 myRef에 User 객체를 하나 상승하여 저장해주면 끝입니다.
그럼 아래와 같이 사용자가 추가된 것을 firebase console에서 확인할 수 있습니다.
한가지 주의해야 할 점은,
저장하고자 하는 객체의 클래스에는 기본 생성자가 정의되어 있어야 합니다.
기본 생성자가 없다면 Exception이 발생하게 되니 참고하시기 바랍니다.
데이터를 삭제하는 것은 훨씬 더 간단합니다.
다음 코드에서 위에서 추가한 사용자 "abc"를 삭제합니다.
제일 간단할 것 같지만, Read가 제일 까다롭습니다.
처음에 write, delete 예제만 봤을 땐 다음과 같이 하면 될 줄 알았습니다.
하지만 어떻게 해봐도 객체를 Read하는 메서드는 존재하지 않았습니다.
다시 문서를 확인한 결과,
Read를 위해서는 ValueEventListener를 DatabaseReference에 추가해주어야 하며,
읽어 온 데이터를 사용하기 위해서는 callback 구조를 사용하는 것이 자연스럽습니다.
우선 Read하는 것은 다음과 같습니다.
위 코드를 통해 "abc" 사용자를 객체 형태로 읽어올 수 있습니다.
그런데 제가 말씀드린 callback 구조가 어떤 의미인가 싶을텐데요.
간단히 다음과 같은 로직이 있다고 생각해보죠.
userId 를 인자로 넘겨주어 Firebase Realtime Database에서 해당하는 User 객체를 받아 return 하는 메서드입니다.
그러나 이를 실행해보면 항상 null이 반환됩니다.
myRef에서 Listener를 걸어두기만 하고 바로 null 값의 user를 return 한 뒤,
이 ValueEventListener는 이후에 동작하기 때문입니다.
그렇기 때문에 보통의 경우는 다음과 같이 callback 구조로 사용합니다.
이러한 callback 방식이 android app 개발에 자주 쓰이는 패턴인지는 모르겠습니다만,
Firebase Realtime Database 를 사용한다면 익숙해져야 할 것 같습니다.
그리고 이러한 방식이 Android에서 MVP 패턴을 사용하는데 대표적인 예제가 되지 싶습니다.
너무도 막강해서 마치 마법같이 느껴지고
이러한 기능을 제공하는 구글에 감탄하게 됩니다.
그 첫 번째 감동으로 Realtime Database에 대해 간단히 소개합니다.
Firebase Realtime Database를 간단히 소개하자면
Cloud Database라고 할 수 있습니다.
Cloud Database이기 때문에 플랫폼 종속성이 없습니다.
실제 Firebase의 다른 모든 기능들이 Android, IOS, Web, Server 플랫폼에서 자유롭게 사용 가능하죠.
그럼 Cloud이기 때문에 온라인이 아닌 상황(인터넷 접속이 안되는 상황)에서는 사용이 불가하냐?
그것도 아닙니다.
데이터를 디스크에 유지하므로 오프라인일 때에도 문제없이 사용가능합니다.
이후 네트워크에 연결되면 데이터를 자동으로 동기화시켜주기 때문에 네트워크에 대한 걱정은 접으시기 바랍니다.
개인적으로 저 역시 Android/Firebase를 이제 입문하여 학습/적용하는 단계이기 때문에
자세한 내용은 알지 못합니다만
한가지 의문점이 생깁니다.
과연 SQLite를 사용한 내부 데이터 저장소를 앞으로도 사용할 필요가 있을까?
특히나 요즘 같이
빵빵한 네트워크 환경,
고성능의 디바이스,
무엇보다 빅데이터 분석을 통한 차별화된 서비스 제공
등을 고려하면 서버로의 데이터 취합은 필수로 보입니다.
그리고 빠른 트렌드 변화에 유연하게 대응하기 위해서는 실제 물리 서버 구축보다는 Cloud를 이용하는 것이 강점이 될 것이고요.
그런 점에서 구글에서 제공하는 Firebase Realtime Database는 개발자들에게 큰 무기가 되지 않나 싶습니다.
다만 한가지 염두에 두어야 할 점은 Realtime Database는 익히 알고 있는 관계형 데이터베이스(RDBMS)는 아니라는 것입니다.
Realtime Database에서는 데이터들이 아래와 같이 json 형식으로 저장되기 때문에
관계형 데이터베이스와는 다른 데이터 구조를 생각해야 합니다.
{ "users": { "alovelace": { "name": "Ada Lovelace", "contacts": { "ghopper": true }, }, "ghopper": { ... }, "eclarke": { ... } } }(출처: https://firebase.google.com/docs/database/android/structure-data)
성능과 데이터 중복, 그리고 트랜잭션 관리 등 생각해야할 요소들이 좀 있을 것 같습니다.
이런 자세한 이야기는 우선 나중으로 미루고,
당장 그럼 어떻게 데이터를 쓰고/읽고/수정하고/삭제하는지.
기본적인 CRUD에 대해 소개하겠습니다.
그 구현 난이도에 따라 다음 순서로 이야기를 시작하도록 하겠습니다.
1. Firebase Realtime Database 접근을 위한 DataSource 얻기
2. 데이터 Write 하기
3. 데이터 Delete 하기
4. 데이터 Read 하기
본 포스팅은 Google Firebase 공식 문서를 참조하여 작성되었습니다.
https://firebase.google.com/docs/database/android/start/
1. Firebase Realtime Database 접근을 위한 DataSource 얻기
Google에서 제공하는 Firebase Realtime Database 를 Android 환경에서 어떻게 사용하는지,그 첫 단계로 Android Project에 환경 구축하는 방법에 대해 소개합니다.
app 수준의 build.gradle에 아래와 같이 firebase database를 추가합니다.
compile 'com.google.firebase:firebase-database:10.0.1'Firebase Realtime Database에 접근하기 위한 DataSource는 아래와 같이 얻습니다.
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference myRef = database.getReference("users");
실제 Firebase Realtime Database에 저장된 데이터들은 다음과 같습니다.
최상위 mandal-art 데이터베이스 안에 mandalarts, plans, users 와 같이 3개의 항목이 존재하고
users 안에 제 이메일 주소를 베이스로한 데이터가 저장되어 있습니다.
(저는 개인적으로 이 mandalarts, plans, users를 각각의 테이블로 이해를 하고 접근을 하였습니다.)
위 코드는 해당 프로젝트의 데이터베이스에서 users 영역에 대한 DatabaseReference를 얻는 코드라고 보면 됩니다.
개발자는 이 DatabaseReference (myRef)를 통해 CRUD 작업을 진행할 수 있습니다.
2. 데이터 Write 하기
위 데이터베이스에 신규 사용자를 추가한다고 하면위에서 얻은 myRef에 User 객체를 하나 상승하여 저장해주면 끝입니다.
1 2 3 | User user = new User(); user.setId("abc"); myRef.child("abc").setValue(user); |
그럼 아래와 같이 사용자가 추가된 것을 firebase console에서 확인할 수 있습니다.
한가지 주의해야 할 점은,
저장하고자 하는 객체의 클래스에는 기본 생성자가 정의되어 있어야 합니다.
기본 생성자가 없다면 Exception이 발생하게 되니 참고하시기 바랍니다.
3. 데이터 Delete 하기
데이터를 삭제하는 것은 훨씬 더 간단합니다.
다음 코드에서 위에서 추가한 사용자 "abc"를 삭제합니다.
1 | myRef.child("abc").removeValue(); |
4. 데이터 Read 하기
제일 간단할 것 같지만, Read가 제일 까다롭습니다.
처음에 write, delete 예제만 봤을 땐 다음과 같이 하면 될 줄 알았습니다.
1 | myRef.child("abc").getValue(); |
하지만 어떻게 해봐도 객체를 Read하는 메서드는 존재하지 않았습니다.
다시 문서를 확인한 결과,
Read를 위해서는 ValueEventListener를 DatabaseReference에 추가해주어야 하며,
읽어 온 데이터를 사용하기 위해서는 callback 구조를 사용하는 것이 자연스럽습니다.
우선 Read하는 것은 다음과 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // Read from the database myRef.child("abc").addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // This method is called once with the initial value and again // whenever data at this location is updated. User user = dataSnapshot.getValue(User.class); Log.d(TAG, "user name is: " + user.getName()); } @Override public void onCancelled(DatabaseError error) { } }); |
위 코드를 통해 "abc" 사용자를 객체 형태로 읽어올 수 있습니다.
그런데 제가 말씀드린 callback 구조가 어떤 의미인가 싶을텐데요.
간단히 다음과 같은 로직이 있다고 생각해보죠.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public User getUser(String userId) { User user = null; myRef.child("abc").addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { user = dataSnapshot.getValue(User.class); } @Override public void onCancelled(DatabaseError error) { } }); return user; } |
userId 를 인자로 넘겨주어 Firebase Realtime Database에서 해당하는 User 객체를 받아 return 하는 메서드입니다.
그러나 이를 실행해보면 항상 null이 반환됩니다.
myRef에서 Listener를 걸어두기만 하고 바로 null 값의 user를 return 한 뒤,
이 ValueEventListener는 이후에 동작하기 때문입니다.
그렇기 때문에 보통의 경우는 다음과 같이 callback 구조로 사용합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | // 아래 코드는 User 객체를 얻어와 TextView에 사용자 이름을 표시하는 메서드입니다. public void showUserName() { getUser("abc", new LoadUserCallback() { @Override public void onUserLoaded(User user) { textView.setText(user.getName()); } }); } // 실제로 Firebase Realtime Database에서 User 객체를 조회한 뒤 callback 메서드를 호출해줍니다. public void getUser(@NonNull final String userId, @NonNull final LoadUserCallback callback) { ref.child("users").addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { if (dataSnapshot.hasChild(userId)) { User user = dataSnapshot.child(userId).getValue(User.class); callback.onUserLoaded(user); } } @Override public void onCancelled(DatabaseError databaseError) { } }); } |
이러한 callback 방식이 android app 개발에 자주 쓰이는 패턴인지는 모르겠습니다만,
Firebase Realtime Database 를 사용한다면 익숙해져야 할 것 같습니다.
그리고 이러한 방식이 Android에서 MVP 패턴을 사용하는데 대표적인 예제가 되지 싶습니다.
댓글
댓글 쓰기