问题
In my activities, I have a list of strings which represent firestore documents to which I want to attach snapshot listeners. I use Acivity - ModelView - Repository structure. In the acitivity's onCreate, I ask ViewModelProvider for the appropriate ViewModel. In the ViewModel constructor, I make a call to get a repository (as per the "Android room with a view" tutorial"). My repositories are in charge of attaching firestore listeners and sync the online data into my local DB (android room).
I used to have memory leaks with those listeners, i.e. every time a firestore document changed, my repository was trying to download two, three, four..copies of it into the local DB! I solved that problem by making a call from my activities' onDestroy all the way up to the repository to remove the listeners.
My question is about the pricing of this solution. I read on the FireBase website that a snapshot listener will count at least as one "document read" everytime it is launched, even if no changes to the document are ever made. Basically, I am removing and re-attaching a dozen or so listeners (to the exact same documents) every time a user switches activities in my app. Does this mean I am paying a document read for every one of those activity changes even if the 30-minute limit isn't up yet?
Activity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMessageViewModel = new ViewModelProvider(this).get(MessageViewModel.class);
// ....
}
@Override
public void onDestroy(){
mMessageViewModel.removeListeners();
super.onDestroy();
}
ViewModel
public MessageViewModel (Application application) {
super(application);
mRepository = new MessageRepository(application);
}
public void removeListeners(){
mRepository.removeListeners();
}
// ...
Repository
private List<ListenerRegistration> my_listeners;
private List<String> my_list;
MessageRepository(Application application) {
MessageRoomDatabase db = MessageRoomDatabase.getDatabase(application);
mMessageDao = db.messageDao();
firedb = FirebaseFirestore.getInstance();
attachListeners();
}
public void attachListeners(){
for(String item : my_list){
colRef = firedb.collection("items").document(item).collection("sub-items");
ListenerRegistration my_listener_registration = colRef
.addSnapshotListener(myListener);
my_listeners.add(my_listener_registration);
}
}
public void removeListeners(){
for(ListenerRegistration my_listener : my_listeners){
my_listener.remove();
}
}
// ...
回答1:
Every time you attach a listener, the Firestore client has to connect to the server to check if the documents observed by that listener have been modified. Since the server has to read the document for that, you will indeed be charged for a document read for each document that you observe.
If you don't want this, you can consider telling the client to read from the cache by specifying that in the source options.
DocumentReference docRef = db.collection("cities").document("SF"); // Source can be CACHE, SERVER, or DEFAULT. Source source = Source.CACHE; // Get the document, forcing the SDK to use the offline cache docRef.get(source).addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() { ...
Since this reads from the local cache, you won't be charged for a read on the server, but of course that means you may be serving stale data.
来源:https://stackoverflow.com/questions/59419258/what-relationship-between-firestore-snapshotlisteners-lifecycle-and-pricing