Во-первых, если вы этого еще не сделали, прочитайте документацию о возможностях автономного режима , чтобы вы получили общее представление о том, как Firebase ведет себя в автономном режиме.
Далее мы Вычистим ваши операции записи так, чтобы они представляли собой одну операцию атома c, а не несколько отдельных операций записи.
HashMap<String, Object> tripData = new HashMap<>();
tripData.put("phone", phone_val);
tripData.put("comment", comment_val);
tripData.put("type", 1);
DatabaseReference newTrip = mDatabase.push();
newTrip.setValue(tripData);
Как указано в документации по возможностям автономного режима, вы можете проверить, находится ли ваше приложение в автономном режиме. проверяя специальное местоположение базы данных /.info/connected
, которое возвращает текущее состояние соединения . Это значение будет либо true
, либо false
.
Хотя вы можете проверить это значение перед публикацией своих поездок, состояние соединения может измениться во время отправки данных.
Даже если вы добавите данные после этого, автономный пост останется последним.
Это самая сложная часть для управления. Я думаю, что самый простой способ справиться с этим - это иметь «промежуточный» раздел вашей базы данных, а затем перемещать данные по мере их создания в этом месте в основное хранилище, используя облачную функцию для Firebase .
Клиентская сторона
Допустим, вы храните эти поездки в /trips/someTripId
.
private DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
private DatabaseReference mAllTripsRef = mDatabase.child('trips');
Чтобы добавить новую поездку, вы должны использовать:
HashMap<String, Object> tripData = new HashMap<>();
tripData.put("phone", phone_val);
tripData.put("comment", comment_val);
tripData.put("type", 1);
DatabaseReference mNewTripRef = mAllTripsRef.push();
mNewTripRef.setValue(tripData);
Поскольку ссылки, созданные с помощью push()
, основаны на оценочном времени серверов Firebase, они будут упорядочены по времени их создания, а не когда они будут получены серверами Firebase. Но если вы хотите сохранить, что автономные поездки всегда будут последними, вместо того, чтобы записывать новые поездки в /trips
, вы бы вместо этого записали в /trips-staging
.
private DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
// trips that have been posted to "online" database
private DatabaseReference mAllTripsRef = mDatabase.child('trips');
// trips yet to be posted online
private DatabaseReference mStagingTripsRef = mDatabase.child('trips-staging');
Новые данные будут добавлены с использованием:
HashMap<String, Object> tripData = new HashMap<>();
tripData.put("phone", phone_val);
tripData.put("comment", comment_val);
tripData.put("type", 1);
DatabaseReference mNewTripRef = stagingTripsRef.push();
mNewTripRef.setValue(tripData);
Теперь, когда у нас есть ссылка на поездку, ожидающую публикации, mNewTripRef
, мы можем добавить к ней прослушиватель, чтобы увидеть, когда она была опубликована.
В облачной части ниже мы собираемся сделать так, чтобы при наличии данных на /trips-staging/someTripId
, а это просто строка, поездка была получена и отправлена сервером в местоположение /trips/<string-value>
.
ValueEventListener stagingTripListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get trip data
Object tripData = dataSnapshot.getValue();
if (tripData == null) {
// Data has been deleted!
// Disconnect this listener
mNewTripRef.removeEventListener(this);
// TODO: What now?
} else if (tripData instanceof String) {
// Data has been moved!
DatabaseReference postedTripRef = mAllTripsRef.child((String) tripData);
// Disconnect this listener
mNewTripRef.removeEventListener(this);
Log.i(TAG, "stagingTripListener:onDataChange", "New trip has been successfully posted as trip '" + mNewTripRef.getKey() + "'");
// TODO: do something with postedTripRef
} else {
// ignore - the trip hasn't been moved yet, continue waiting
// tripData is a Map<string, Object> with our original data
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
// Getting this trip failed, log a message
Log.w(TAG, "stagingTripListener:onCancelled", databaseError.toException());
}
};
mNewTripRef.addValueEventListener(stagingTripListener);
Cloud Side
Теперь нам нужно переместить эти новые поездки в /trips
, как только они будут получены на сервере. Для этого мы можем использовать облачную функцию для Firebase , которая прослушивает события базы данных реального времени . В нашем случае мы хотим исключительно прослушивать события создания данных , которые происходят в нашем /trips-staging
местоположении.
Когда запускается функция Cloud, она должна принимать данные в /trips-staging/someId
и переместите его на /trips/someNewId
. Вероятно, это также хорошая идея - хранить данные о том, куда мы переместили данные, в старое место, если это когда-либо понадобится, но также и для того, чтобы мы могли определить, когда поездка была получена сервером.
После выполнения Приступая к работе Документация до шага 4, вы можете использовать следующий код в качестве файла index.js
или index.ts
, а затем развернуть его, используя firebase deploy --only functions
.
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp(); // use defaults
export const moveTripsFromStaging = functions.database.ref('/trips-staging/{stagingTripId}')
.onCreate((snapshot, context) => {
const stagingTripId = snapshot.key;
const tripData = snapshot.val();
// get reference to the root of the database
let dbRootRef = admin.database().ref();
let allTripsRef = dbRootRef.child('trips');
let newTripRef = allTripsRef.push();
return dbRootRef.update({
// move data to it's new home
['trips/' + newTripRef.key]: tripData,
// save where we moved data to as a simple string containing the new key in /trips
['trips-staging/' + stagingTripId]: newTripRef.key // or set to null to delete it
});
})
После развертывания, вы должны увидеть, как новые поездки, загруженные на /trips-staging
, будут получены сервером, а затем перенесены на /trips
в порядке, в котором их получает сервер.