Android
Firebase 실시간 데이터베이스
수색…
비고
Firebase Realtime DataBase 이벤트 핸들러
먼저 FirebaseDatabase 초기화 :
FirebaseDatabase database = FirebaseDatabase.getInstance();
데이터베이스에 쓰기 :
// Write a message to the database
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("message");
myRef.setValue("Hello, World!");
데이터베이스에서 읽기 :
// Read from the database
myRef.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.
String value = dataSnapshot.getValue(String.class);
Log.d(TAG, "Value is: " + value);
}
@Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
});
Android 이벤트에서 데이터 검색 :
ChildEventListener childEventListener = new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "postComments:onCancelled", databaseError.toException());
Toast.makeText(mContext, "Failed to load comments.",
Toast.LENGTH_SHORT).show();
}
};
ref.addChildEventListener(childEventListener);
빠른 설치
앱을 Firebase에 연결하려면 설치 및 설정 부분 을 완료하십시오.
그러면 Firebase에 프로젝트가 생성됩니다.Firebase Realtime Database에 대한 의존성을 모듈 수준
build.gradle
파일에build.gradle
하십시오 :
compile 'com.google.firebase:firebase-database:10.2.1'
이제 Android에서 실시간 데이터베이스로 작업 할 준비가되었습니다.
예를 들어, Hello World
메시지를 message
키 아래의 데이터베이스에 씁니다.
// Write a message to the database
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("message");
myRef.setValue("Hello, World!");
Firebase 데이터베이스에서 실시간 데이터를 검색하는 방법 설계 및 이해
이 예제는 이미 Firebase Realtime Database를 설정했다고 가정합니다. 당신이 초보 인 경우에, 자신을 알려 주시기 바랍니다 여기 당신의 안드로이드 프로젝트에 중포 기지를 추가하는 방법에.
먼저 Firebase 데이터베이스의 종속성을 app 수준 build.gradle 파일에 추가 합니다.
compile 'com.google.firebase:firebase-database:9.4.0'
이제 Firebase 데이터베이스에 데이터를 저장하는 채팅 앱을 만들어 보겠습니다.
1 단계 : 채팅이라는 클래스 만들기
채팅에 필요한 몇 가지 기본 변수가있는 클래스를 만듭니다.
public class Chat{
public String name, message;
}
2 단계 : 일부 JSON 데이터 만들기
파이어베이스 데이터베이스와 데이터를 송수신하려면 JSON을 사용해야합니다. 일부 채팅은 이미 데이터베이스의 루트 수준에 저장되어 있다고 가정합니다. 이 채팅의 데이터는 다음과 같습니다.
[
{
"name":"John Doe",
"message":"My first Message"
},
{
"name":"John Doe",
"message":"Second Message"
},
{
"name":"John Doe",
"message":"Third Message"
}
]
3 단계 : 리스너 추가
청취자에는 세 가지 유형이 있습니다. 다음 예제에서는 childEventListener
를 사용하려고합니다.
DatabaseReference chatDb = FirebaseDatabase.getInstance().getReference() // Referencing the root of the database.
.child("chats"); // Referencing the "chats" node under the root.
chatDb.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
// This function is called for every child id chat in this case, so using the above
// example, this function is going to be called 3 times.
// Retrieving the Chat object from this function is simple.
Chat chat; // Create a null chat object.
// Use the getValue function in the dataSnapshot and pass the object's class name to
// which you want to convert and get data. In this case it is Chat.class.
chat = dataSnapshot.getValue(Chat.class);
// Now you can use this chat object and add it into an ArrayList or something like
// that and show it in the recycler view.
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
// This function is called when any of the node value is changed, dataSnapshot will
// get the data with the key of the child, so you can swap the new value with the
// old one in the ArrayList or something like that.
// To get the key, use the .getKey() function.
// To get the value, use code similar to the above one.
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
// This function is called when any of the child node is removed. dataSnapshot will
// get the data with the key of the child.
// To get the key, use the s String parameter .
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
// This function is called when any of the child nodes is moved to a different position.
// To get the key, use the s String parameter.
}
@Override
public void onCancelled(DatabaseError databaseError) {
// If anything goes wrong, this function is going to be called.
// You can get the exception by using databaseError.toException();
}
});
4 단계 : 데이터베이스에 데이터 추가
Chat 클래스 객체를 만들고 다음과 같이 값을 추가하면됩니다.
Chat chat=new Chat();
chat.name="John Doe";
chat.message="First message from android";
검색 세션에서 수행 된 것처럼 채팅 노드에 대한 참조를 가져옵니다.
DatabaseReference chatDb = FirebaseDatabase.getInstance().getReference().child("chats");
데이터를 추가하기 전에 채팅 노드에 노드가 여러 개 있고 새 채팅을 추가하면 채팅 세부 정보가 포함 된 새 노드를 추가한다는 의미이므로 한 번 더 심도 깊은 참조가 필요하다는 점에 유의하십시오. 우리는 DatabaseReference
객체에서 push()
함수를 사용하여 노드의 새롭고 고유 한 이름을 생성 할 수 있습니다.이 함수는 또 다른 DatabaseReference
를 반환하며,이 노드는 채팅 데이터를 삽입하기 위해 새로 형성된 노드를 가리 킵니다.
예
// The parameter is the chat object that was newly created a few lines above.
chatDb.push().setValue(chat);
setValue()
함수는 응용 프로그램의 onDataChanged
함수가 모두 (동일한 장치를 포함하여) 호출되고 있는지 확인합니다.이 함수는 "chats"노드의 연결된 수신기입니다.
비정규 화 : 플랫 데이터베이스 구조
비정규 화 및 플랫 데이터베이스 구조는 별도의 호출을 효율적으로 다운로드하는 데 필요합니다. 다음과 같은 구조로 양방향 관계를 유지할 수도 있습니다. 이 접근법의 단점은 항상 여러 위치에서 데이터를 업데이트해야한다는 것입니다.
예를 들어, 사용자가 메시지를 자신 (메모)에 저장할 수있는 앱을 상상해보십시오.
원하는 플랫 데이터베이스 구조 :
|--database
|-- memos
|-- memokey1
|-- title: "Title"
|-- content: "Message"
|-- memokey2
|-- title: "Important Title"
|-- content: "Important Message"
|-- users
|-- userKey1
|-- name: "John Doe"
|-- memos
|-- memokey1 : true //The values here don't matter, we only need the keys.
|-- memokey2 : true
|-- userKey2
|-- name: "Max Doe"
사용 된 메모 클래스
public class Memo {
private String title, content;
//getters and setters ...
//toMap() is necessary for the push process
private Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
result.put("title", title);
result.put("content", content);
return result;
}
}
사용자의 메모 검색
//We need to store the keys and the memos seperately
private ArrayList<String> mKeys = new ArrayList<>();
private ArrayList<Memo> mMemos = new ArrayList<>();
//The user needs to be logged in to retrieve the uid
String currentUserId = FirebaseAuth.getInstance().getCurrentUser().getUid();
//This is the reference to the list of memos a user has
DatabaseReference currentUserMemoReference = FirebaseDatabase.getInstance().getReference()
.child("users").child(currentUserId).child("memos");
//This is a reference to the list of all memos
DatabaseReference memoReference = FirebaseDatabase.getInstance().getReference()
.child("memos");
//We start to listen to the users memos,
//this will also retrieve the memos initially
currentUserMemoReference.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
//Here we retrieve the key of the memo the user has.
String key = dataSnapshot.getKey(); //for example memokey1
//For later manipulations of the lists, we need to store the key in a list
mKeys.add(key);
//Now that we know which message belongs to the user,
//we request it from our memos:
memoReference.child(key).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Here we retrieve our memo:
Memo memo = dataSnapshot.getValue(Memo.class);
mMemos.add(memo);
}
@Override
public void onCancelled(DatabaseError databaseError) { }
});
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) { }
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) { }
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) { }
@Override
public void onCancelled(DatabaseError databaseError) { }
}
메모 만들기
//The user needs to be logged in to retrieve the uid
String currentUserUid = FirebaseAuth.getInstance().getCurrentUser().getUid();
//This is the path to the list of memos a user has
String userMemoPath = "users/" + currentUserUid + "/memos/";
//This is the path to the list of all memos
String memoPath = "memos/";
//We need to retrieve an unused key from the memos reference
DatabaseReference memoReference = FirebaseDatabase.getInstance().getReference().child("memos");
String key = memoReference.push().getKey();
Memo newMemo = new Memo("Important numbers", "1337, 42, 3.14159265359");
Map<String, Object> childUpdates = new HashMap<>();
//The second parameter **here** (the value) does not matter, it's just that the key exists
childUpdates.put(userMemoPath + key, true);
childUpdates.put(memoPath + key, newMemo.toMap());
FirebaseDatabase.getInstance().getReference().updateChildren(childUpdates);
푸시 또는 데이터베이스가 다음과 같이 표시되면 다음을 수행합니다.
|--database
|-- memos
|-- memokey1
|-- title: "Title"
|-- content: "Message"
|-- memokey2
|-- title: "Important Title"
|-- content: "Important Message"
|-- generatedMemokey3
|-- title: "Important numbers"
|-- content: "1337, 42, 3.14159265359"
|-- users
|-- userKey1
|-- name: "John Doe"
|-- memos
|-- memokey1 : true //The values here don't matter, we only need the keys.
|-- memokey2 : true
|-- generatedMemokey3 : true
|-- userKey2
|-- name: "Max Doe"
firebase JSON 데이터베이스 이해하기
코드로 손을 더럽 히기 전에 데이터가 firebase에 저장되는 방식을 이해해야한다고 생각합니다. 관계형 데이터베이스와 달리 firebase는 JSON 형식으로 데이터를 저장합니다. 관계형 데이터베이스의 각 행을 JSON 객체 (기본적으로 정렬되지 않은 키 - 값 쌍)라고 생각하십시오. 따라서 열 이름이 키가되며 특정 행에 대해 해당 열에 저장된 값이 값이됩니다. 이렇게하면 전체 행이 JSON 객체로 표시되고 이들의 목록은 전체 데이터베이스 테이블을 나타냅니다. 내가보기에 즉각적인 이점은 오래된 RDBMS에 비해 스키마 수정 작업이 훨씬 저렴하다는 점입니다. 테이블 구조를 변경하는 것보다 JSON에 두 가지 이상의 속성을 추가하는 것이 더 쉽습니다.
다음은 데이터가 firebase에 저장되는 방법을 보여주는 샘플 JSON입니다.
{
"user_base" : {
"342343" : {
"email" : "[email protected]",
"authToken" : "some string",
"name" : "Kaushal",
"phone" : "+919916xxxxxx",
"serviceProviderId" : "firebase",
"signInServiceType" : "google",
},
"354895" : {
"email" : "[email protected]",
"authToken" : "some string",
"name" : "devil",
"phone" : "+919685xxxxxx",
"serviceProviderId" : "firebase",
"signInServiceType" : "github"
},
"371298" : {
"email" : "[email protected]",
"authToken" : "I am batman",
"name" : "Bruce Wayne",
"phone" : "+14085xxxxxx",
"serviceProviderId" : "firebase",
"signInServiceType" : "shield"
}
},
"user_prefs": {
"key1":{
"data": "for key one"
},
"key2":{
"data": "for key two"
},
"key3":{
"data": "for key three"
}
},
//other structures
}
이는 관계형 데이터베이스에 저장 한 데이터를 JSON 형식으로 저장하는 방법을 명확하게 보여줍니다. 다음으로이 데이터를 Android 기기에서 읽는 방법을 알아 보겠습니다.
firebase에서 데이터 가져 오기
안드로이드 스튜디오에서 gradle dependencies firebase를 추가하는 것에 대해 이미 알고 있다고 가정합니다. 만약 당신이 여기 에서 가이드를 따르지 않는다면. 종속성을 추가 한 후 firebase 콘솔, gradle sync android studio에 앱을 추가하십시오. firebase database와 firebase auth만이 모든 의존성을 필요로하지 않습니다.
데이터가 저장되는 방법과 gradle 의존성을 추가하는 방법을 알았으므로 가져온 firebase android SDK를 사용하여 데이터를 검색하는 방법을 살펴 보겠습니다.
firebase 데이터베이스 참조 만들기
DatabaseReference userDBRef = FirebaseDatabase.getInstance().getReference();
// above statement point to base tree
userDBRef = DatabaseReference.getInstance().getReference().child("user_base")
// points to user_base table JSON (see previous section)
여기에서 관심있는 데이터를 가리 키도록 여러 child () 메소드 호출을 연결할 수 있습니다. 예를 들어 이전 섹션에서 설명한대로 데이터가 저장되어 있고 Bruce Wayne 사용자를 가리 키려는 경우 다음을 사용할 수 있습니다.
DatabaseReference bruceWayneRef = userDBRef.child("371298");
// 371298 is key of bruce wayne user in JSON structure (previous section)
또는 전체 참조를 JSON 객체에 전달하기 만하면됩니다.
DatabaseReference bruceWayneRef = DatabaseReference.getInstance().getReference()
.child("user_base/371298");
// deeply nested data can also be referenced this way, just put the fully
// qualified path in pattern shown in above code "blah/blah1/blah1-2/blah1-2-3..."
가져 오려는 데이터에 대한 참조가 있으므로 이제는 리스너를 사용하여 Android 앱에서 데이터를 가져올 수 있습니다. retrofit 또는 발리 슛을 사용하여 REST API 호출을 실행하는 기존 호출과 달리 여기에서는 간단한 콜백 수신기가 데이터를 가져와야합니다. Firebase SDK가 콜백 메소드를 호출하면 완료됩니다.
기본적으로 두 가지 유형의 리스너를 연결할 수 있습니다. 하나는 ValueEventListener 이고 다른 하나는 ChildEventListener입니다 (다음 섹션에서 설명). 참조가 있고 추가 된 리스너가있는 노드 아래의 데이터가 변경되면 값 이벤트 리스너가 전체 JSON 구조를 반환하고 자식 이벤트 리스너가 변경이 발생한 특정 자식을 반환합니다. 이 두 가지 방법 모두 유용합니다. firebase에서 데이터를 가져 오기 위해 하나 이상의 리스너를 firebase 데이터베이스 참조에 추가 할 수 있습니다 (이전에 생성 한 userDBRef 목록).
다음은 몇 가지 샘플 코드입니다 (코드 설명 후 코드 설명).
userDBRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
User bruceWayne = dataSnapshot.child("371298").getValue(User.class);
// Do something with the retrieved data or Bruce Wayne
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.e("UserListActivity", "Error occured");
// Do something about the error
});
전달 된 클래스 유형을 확인 했습니까? DataSnapshot 은 JSON 데이터를 정의 된 POJO로 변환 할 수 있으며 간단한 클래스 유형을 전달합니다.
약간의 변경이 발생할 때마다 유스 케이스 (예 : user_base 테이블) 전체 데이터가 필요하지 않거나 데이터를 한 번만 가져 오려면 데이터베이스 참조의 addListenerForSingleValueEvent () 메소드를 사용할 수 있습니다. 콜백이 한 번만 발생합니다.
userDBRef.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Do something
}
@Override
public void onCancelled(DatabaseError databaseError) {
// Do something about the error
});
위 샘플은 JSON 노드의 가치를 제공합니다. 열쇠를 얻으려면 간단히 다음과 같이하십시오.
String myKey = dataSnapshot.getKey();
아동 업데이트 청취
채팅 앱이나 협업 식료품 점 앱과 같은 유스 케이스를 가져 와서 (기본적으로 사용자간에 개체 목록을 동기화해야 함). firebase 데이터베이스를 사용하고 채팅 부모 노드 또는 식료품 목록 부모 노드에 값 이벤트 리스너를 추가하면 채팅 노드가 추가 될 때마다 (처음 채팅을 시작할 때를 의미 함) 전체 채팅 구조로 끝납니다 ie 누군가는 안녕 말한다). 우리가 원하지 않는 것은, 우리가 관심있는 것은 새로운 노드 또는 삭제되거나 수정 된 이전 노드뿐입니다. 변하지 않은 노드는 반환되지 않습니다.
이 경우 ChildEvenListener 를 사용할 수 있습니다. 더 이상의 도움이 필요하지 않은 코드 샘플은 다음과 같습니다 (샘플 JSON 데이터에 대한 이전 섹션 참조).
userDBRef.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
//If not dealing with ordered data forget about this
}
@Override
public void onCancelled(DatabaseError databaseError) {
});
메서드 이름은 자체 설명입니다. 새 사용자가 추가되거나 기존 사용자의 일부 속성이 수정되거나 사용자가 삭제되거나 제거 될 때마다 알 수 있듯이 관련 이벤트가 발생하면 해당 이벤트에 대한 적절한 콜백 메소드가 호출됩니다. 따라서 채팅 앱에 대해 UI가 새로 고쳐지면 onChildAdded ()에서 JSON을 POJO로 구문 분석하고 UI에 맞 춥니 다. 사용자가 화면을 떠날 때 청취자를 제거하는 것을 잊지 마십시오.
onChildChanged ()는 변경된 속성 (새 속성)을 가진 전체 자식 값을 제공합니다.
onChildRemoved ()는 제거 된 자식 노드를 반환합니다.
페이지 매김을 사용하여 데이터 검색
거대한 JSON 데이터베이스를 가지고있을 때 값 이벤트 리스너를 추가하는 것은 의미가 없습니다. 거대한 JSON을 반환하고 구문 분석에 시간이 많이 걸릴 것입니다. 이 경우 페이지 매김을 사용하여 데이터의 일부를 가져 와서 표시하거나 처리 할 수 있습니다. 게으른로드 중 또는 오래된 채팅을 가져 오는 것과 같이 사용자가 이전 채팅을 클릭하면 표시됩니다. 이 경우 쿼리 를 사용할 수 있습니다.
이전 섹션에서 예전 예제를 보겠습니다. 사용자 수가 3 명이고 사용자가 30 만 명으로 늘어 났을 때 사용자 목록을 50 개 단위로 가져 오려면 다음과 같이하십시오.
// class level
final int limit = 50;
int start = 0;
// event level
Query userListQuery = userDBRef.orderByChild("email").limitToFirst(limit)
.startAt(start)
userListQuery.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Do something
start += (limit+1);
}
@Override
public void onCancelled(DatabaseError databaseError) {
// Do something about the error
});
여기에 값 또는 하위 이벤트를 추가하고들을 수 있습니다. 질의를 다시 호출하여 다음 50 개를 가져 오십시오. orderByChild () 메소드를 추가해야 합니다.이 메소드 를 사용하지 않으면 작동하지 않습니다. Firebase는 페이지 매김하는 순서를 알아야합니다.