Android
База данных Firebase Realtime
Поиск…
замечания
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 к вашему файлу
build.gradle
уровнеbuild.gradle
:
compile 'com.google.firebase:firebase-database:10.2.1'
- Настройка правил базы данных Firebase
Теперь вы готовы работать с базой данных Realtime в 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. Если вы начинаете, пожалуйста, сообщите здесь, как добавить Firebase в свой проект Android.
Во-первых, добавьте зависимость базы данных Firebase к файлу build.gradle на уровне приложения :
compile 'com.google.firebase:firebase-database:9.4.0'
Теперь давайте создадим чат-приложение, которое хранит данные в базе данных Firebase.
Шаг 1. Создайте класс с именем Чат
Просто создайте класс с некоторыми основными переменными, необходимыми для чата:
public class Chat{
public String name, message;
}
Шаг 2: Создайте некоторые данные JSON
Для отправки / получения данных в / из базы данных Firebase вам необходимо использовать 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");
Прежде чем приступать к добавлению данных, имейте в виду, что вам нужна еще одна глубокая ссылка, поскольку узел чата имеет еще несколько узлов и добавление нового чата означает добавление нового узла, содержащего детали чата. Мы можем сгенерировать новое и уникальное имя узла, используя функцию push()
объекта DatabaseReference
, которая вернет другой DatabaseReference
, который, в свою очередь, указывает на вновь образованный узел, чтобы вставить данные чата.
пример
// The parameter is the chat object that was newly created a few lines above.
chatDb.push().setValue(chat);
Функция setValue()
будет обеспечивать, чтобы все функции onDataChanged
приложения onDataChanged
(включая одно и то же устройство), что является приложенным слушателем узла «чаты».
Денормализация: плоская структура базы данных
Денормализация и плоская структура базы данных необходимы для эффективной загрузки отдельных вызовов. Со следующей структурой также можно поддерживать двусторонние отношения. Недостатком такого подхода является то, что вам всегда нужно обновлять данные в нескольких местах.
Например, представьте приложение, которое позволяет пользователю хранить сообщения для себя (заметки).
Желаемая плоская структура базы данных:
|--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"
Используемый класс memo
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"
Понимание базы данных JSON базы Firebase
Прежде чем мы соберём свои руки с кодом, я чувствую, что необходимо понять, как данные хранятся в firebase. В отличие от реляционных баз данных, firebase хранит данные в формате JSON. Подумайте о каждой строке в реляционной базе данных как о объекте JSON (который в основном является неупорядоченной парой ключ-значение). Таким образом, имя столбца становится ключевым, а значение, хранящееся в этом столбце для одной конкретной строки, является значением. Таким образом, вся строка представляется как объект JSON, а список из них представляет собой всю таблицу базы данных. Непосредственная польза, которую я вижу для этого, - это изменение схемы становится намного более дешевой по сравнению со старой РСУБД. Легче добавить еще несколько атрибутов в JSON, чем изменить структуру таблицы.
вот пример JSON, чтобы показать, как данные хранятся в firebase:
{
"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 зависимостей градиента в студии android. Если вы не просто следуете инструкциям отсюда . Добавьте свое приложение в консоль firebase, студию градиента синдрома android после добавления зависимостей. Все зависимости не нужны, просто база данных firebase и firebase auth.
Теперь, когда мы знаем, как хранятся данные и как добавить зависимости gradle, посмотрим, как использовать импортированный SDK для 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. В отличие от традиционных вызовов, в которых вы запускаете вызовы API REST с использованием модификации или волейбола, здесь необходим простой прослушиватель обратного вызова для получения данных. Firebase sdk вызывает методы обратного вызова, и все готово.
В основном есть два типа слушателей, которые вы можете присоединить, один - ValueEventListener, а другой - ChildEventListener (описан в следующем разделе). Для любого изменения данных в узле у нас есть ссылки и добавлены слушатели, функция event eventers возвращает всю структуру 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 table) каждый раз, когда происходит какое-то небольшое изменение или вы хотите получить данные только один раз , вы можете использовать метод 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 и добавляете прослушиватель событий значения к родительскому узлу чата или родительскому узлу списка продуктов, вы будете заканчивать всю структуру чата с самого начала (я имел в виду начало вашего чата) каждый раз, когда добавляется узел чата ( т.е. кто-то говорит привет). То, что мы не хотим делать, нас интересует только новый узел или только старый узел, который был удален или изменен, неизменные не должны возвращаться.
В этом случае мы можем использовать 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) {
});
Имя метода самоочевидно. Как вы можете видеть, когда новый пользователь добавлен или какое-либо свойство существующего пользователя модифицировано, или пользователь удален или удален, соответствующий метод обратного вызова дочернего прослушивателя событий вызывается с соответствующими данными. Поэтому, если вы сохраняете обновленный пользовательский интерфейс для приложения чата, получите JSON из синтаксиса onChildAdded () в POJO и вставьте его в свой пользовательский интерфейс. Просто не забудьте удалить слушателя, когда пользователь покидает экран.
onChildChanged () дает все дочернее значение с измененными свойствами (новые).
onChiledRemoved () возвращает удаленный дочерний узел.
Получение данных с разбиением на страницы
Когда у вас есть огромная база данных JSON, добавление прослушивателя событий значения не имеет смысла. Он вернет огромный JSON и разберется, это потребует много времени. В таких случаях мы можем использовать разбиение на страницы и выборку данных, а также их отображение или обработку. Вроде как ленивая загрузка или как выбор старых чатов, когда пользователь нажимает на старую чат. В этом случае может использоваться запрос .
Давайте рассмотрим наш старый пример в предыдущих разделах. В базе пользователей есть 3 пользователя, если он произносит 3 сотни тысяч пользователей, и вы хотите получить список пользователей в партиях по 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 должен знать порядок, по которому вы разбиваете страницы.