Вот пример фрагмента кода с прослушивателями успеха / неудачи, который работает как в сети, так и в автономном режиме.

вертировал одно из моих приложений в новый Firestore. Я делаю такие вещи, как сохранение документа по нажатию кнопки, а затем вonSuccess слушатель, идущий на другую деятельность.

Я также использую тот факт, что операции сохранения Firestore возвращают задачи, чтобы группировать задачи вместе, используяTasks.whenAll:

val allTasks = Tasks.whenAll(
       createSupporter(supporter),,
       setStreetLookup(makeStreetKey(supporter.street_name)),
       updateCircleChartForUser(statusChange, createMode = true), 
       updateStatusCountForUser(statusChange))

      allTasks.addOnSuccessListener([email protected], successListener)
      allTasks.addOnFailureListener([email protected], onFailureListener)

Наконец, я получаю идентификатор документа из успешного сохранения и сохраняю его в настройках или в локальной базе данных для последующего использования (в пределахonSuccessListener)

Это все прекрасно работает.Пока не будет потеря сетевого подключения, Тогда все рушится, потому что задачи никогда не завершаются, и слушатели onSuccess / onFailure / onComplete никогда не вызываются. Так что приложение просто зависает.

Я работаю над этим, проверяя доступность сети перед каждым сохранением, а затем выполняю обходные пути, создавая задачи без каких-либо слушателей. Я также генерирую идентификатор документа локально с помощью генератора UUID.

Кстати, это было не то, как приложение работало со старой базой данных. В этом случае все работало хорошо в автономном режиме, и я видел, как документы синхронизировались всякий раз, когда приложение выходило в сеть.

Мой обход Firestore кажется ужасным взломом. Кто-нибудь придумал лучшее решение?

Смотрите связанныеБаза данных Firestore для вставки / удаления обратных вызовов документа, не вызываемых, когда нет соединения addOnCompleteListener не вызывается в автономном режиме с облачным пожарным хранилищем

 Dutch Masters19 дек. 2017 г., 07:06
API-интерфейс Task не позволяет вам отменить задачу. Так что вам придется сделать это другим способом.
 Serj Ardovic18 дек. 2017 г., 14:41
Вы пробовали тайм-ауты? Есть несколько способов их реализации, просто выполните действие отмены, когда некоторое время (скажем, 3-5 секунд) истекает.
 Frank van Puffelen23 дек. 2017 г., 19:45
Как говорит Алекс в своем ответе: «Когда происходит потеря сетевого подключения (на пользовательском устройстве нет сетевого подключения), ни onSuccess (), ни onFailure () не запускаются». Так всегда было в базе данных Firebase Realtime: только записи, зафиксированные на сервере, считаются неудачными / успешными до того, как они ожидают.
 Dutch Masters24 дек. 2017 г., 19:24
@Frank Firebase вообще не имеет прослушивателей onSuccess () / onFailure (). Он полностью асинхронный, поэтому, когда что-то может происходить, когда приложение находится в автономном режиме, мне не нужно об этом знать. Это просто работает. Firestore также утверждает, что является асинхронным, но в действительности документы не ясно о различиях.
 Dutch Masters19 дек. 2017 г., 07:08
Следует помнить одну вещь: когда вы добавляете / обновляете с помощью Firestore, он сразу же создает запись в вашем локальном кеше. Затем он пытается синхронизироваться с сервером, когда это возможно. Так что это почти как двухфазный коммит. Но как только данные находятся в локальном кэше, они, похоже, не будут откатываться. Слушатели ждут синхронизации с сервером, но было бы лучше, если бы у слушателя был способ вернуться к локальной синхронизации.

Ответы на вопрос(3)

данные, но вам нужно использовать «Снимок» (QuerySnapshot, DocumentSnapshot), чтобы обработать этот случай, к сожалению, он плохо документирован. Вот пример кода (я использую Kotlin Android) для обработки случая с помощью Snapshot:

ОБНОВЛЕНИЕ ДАННЫХ:

db.collection("members").document(id)
  .addSnapshotListener(object : EventListener<DocumentSnapshot> {
      override fun onEvent(snapshot: DocumentSnapshot?,
                           e: FirebaseFirestoreException?) {
          if (e != null) {
              Log.w(ContentValues.TAG, "Listen error", e)
              err_msg.text = e.message
              err_msg.visibility = View.VISIBLE;
              return
          }
          snapshot?.reference?.update(data)

      }
  })

ДОБАВИТЬ ДАННЫЕ:

db.collection("members").document()
 .addSnapshotListener(object : EventListener<DocumentSnapshot> {
     override fun onEvent(snapshot: DocumentSnapshot?,
                          e: FirebaseFirestoreException?) {
         if (e != null) {
             Log.w(ContentValues.TAG, "Listen error", e)
             err_msg.text = e.message
             err_msg.visibility = View.VISIBLE;
             return
         }
         snapshot?.reference?.set(data)

     }
 })

УДАЛИТЬ ДАННЫЕ:

db.collection("members").document(list_member[position].id)
   .addSnapshotListener(object : EventListener<DocumentSnapshot> {
       override fun onEvent(snapshot: DocumentSnapshot?,
                            e: FirebaseFirestoreException?) {
           if (e != null) {
               Log.w(ContentValues.TAG, "Listen error", e)
               return
           }
           snapshot?.reference?.delete()
       }
   })

Вы можете увидеть пример кода здесь:https://github.com/sabithuraira/KotlinFirestore и сообщение в блогеhttp://blog.farifam.com/2017/11/28/android-kotlin-management-offline-firestore-data-automatically-sync-it/

 Phuah Yee Keat01 сент. 2018 г., 03:40
На самом деле этот метод просто игнорирует будущее, которое возвращается вызовом update (). Если вы установите прослушиватель на вызов update () (даже внутри snapshotlistener), вы все равно увидите, что он НЕ ВЫЗЫВАЕТСЯ. С функциональной точки зрения это все равно, что просто игнорировать будущее. И этот метод имеет проблему, что обновление будет вызываться несколько раз.

http://blog.farifam.com, В основном вы должны использоватьSnapshotListeners вместоOnSuccess слушатели для оффлайн-работы. Кроме того, вы не можете использовать задачи Google, потому что они не будут конкурировать в автономном режиме.

Вместо этого (поскольку задачи в основном обещают), я использовал KotlinKovenant библиотека, которая может прикрепить слушателей к обещаниям. Одно из правил заключается в том, что вы должны настроить Kovenant для разрешения многократного разрешения для обещания, поскольку прослушиватель событий может вызываться дважды (один раз, когда данные добавляются в локальный кэш, и один раз, когда они синхронизируются с сервером).

Вот пример фрагмента кода с прослушивателями успеха / неудачи, который работает как в сети, так и в автономном режиме.

val deferred = deferred<DocumentSnapshot, Exception>() // create a deferred, which holds a promise
// add listeners
deferred.promise.success { Log.v(TAG, "Success! docid=" + it.id) }
deferred.promise.fail { Log.v(TAG, "Sorry, no workie.") }

val executor: Executor = Executors.newSingleThreadExecutor()
val docRef = FF.getInstance().collection("mydata").document("12345")
val data = mapOf("mykey" to "some string")

docRef.addSnapshotListener(executor, EventListener<DocumentSnapshot> { snap: DocumentSnapshot?, e: FirebaseFirestoreException? ->
    val result = if (e == null) Result.of(snap) else Result.error(e)
    result.failure {
        deferred.reject(it) // reject promise, will fire listener
    }
    result.success { snapshot ->
        snapshot.reference.set(data)
        deferred.resolve(snapshot) // resolve promise, will fire listener
    }
})

зовательском устройстве), ниonSuccess() ниonFailure() срабатывают. Такое поведение имеет смысл, поскольку задача считается выполненной только тогда, когда данные были зафиксированы (или отклонены) на сервере Firebase.onComplete(Task<T> task) Метод вызывается также только после завершения Задачи. Так что в случае отсутствия подключения к Интернету, ниonComplete срабатывает.

Нет необходимости проверять доступность сети перед каждым сохранением. Существует обходной путь, который легко может помочь вам понять, действительно ли клиент Firestore не может подключиться к серверу Firebase, которыйenabling debug logging:

FirebaseFirestore.setLoggingEnabled(true);

Операции, которые записывают данные в базу данных Firestore, определены дляsignal completion как только они на самом деле преданы бэкэнду. В результате это работает как задумано: в автономном режиме они не будут сигнализировать о завершении.

Обратите внимание, что клиенты Firestore внутренне гарантируют, что вы можете читать свои собственные записи, даже если вы не ждете завершения задачи от удаления.

 Dutch Masters24 дек. 2017 г., 19:30
Я не вижу, как включение ведения журнала является «обходным путем». Основной вопрос заключается в том, как заставить приложение firestore работать одинаково в автономном режиме и в Интернете. Очевидно, я не хочу, чтобы пользователи целый день ждали, пока слушатели сработают, если их устройство отключится от сети.
 Alex Mamo25 дек. 2017 г., 09:21
Кроме того, если вы хотите проверить, получаете ли вы данные с сервера или из кэша, используйтеfromCache свойство SnapshotMetadata в вашем событии снимка. Если fromCache естьtrueданные поступили из кэша и могут быть неполными. ЕслиfromCache являетсяfalse, данные полны и актуальны с последними обновлениями на сервере.
 Alex Mamo25 дек. 2017 г., 09:19
Вы не можете выполнять работу Firestore, находясь в сети так же, как и в автономном режиме. Вот почему у нас 2 разных поведения, потому что есть два разных состояния. Пока устройство находится в автономном режиме, ваши слушатели будут получать события прослушивания при изменении локально кэшированных данных. Вы можете прослушивать документы, коллекции и запросы, но эти методы будут вызываться только тогда, когда вы вернетесь в оперативный режим, и только когда данные будут зафиксированы или отклонены сервером.

Ваш ответ на вопрос