Firebase Offline Capabilities and addListenerForSingleValueEvent

后端 未结 4 761
无人及你
无人及你 2020-11-21 22:21

Whenever I use addListenerForSingleValueEvent with setPersistenceEnabled(true), I only manage to get a local offline copy of DataSnapshot

4条回答
  •  长发绾君心
    2020-11-21 23:11

    You can create transaction and abort it, then onComplete will be called when online (nline data) or offline (cached data)

    I previously created function which worked only if database got connection lomng enough to do synch. I fixed issue by adding timeout. I will work on this and test if this works. Maybe in the future, when I get free time, I will create android lib and publish it, but by then it is the code in kotlin:

    /**
         * @param databaseReference reference to parent database node
         * @param callback callback with mutable list which returns list of objects and boolean if data is from cache
         * @param timeOutInMillis if not set it will wait all the time to get data online. If set - when timeout occurs it will send data from cache if exists
         */
        fun readChildrenOnlineElseLocal(databaseReference: DatabaseReference, callback: ((mutableList: MutableList<@kotlin.UnsafeVariance T>, isDataFromCache: Boolean) -> Unit), timeOutInMillis: Long? = null) {
    
            var countDownTimer: CountDownTimer? = null
    
            val transactionHandlerAbort = object : Transaction.Handler { //for cache load
                override fun onComplete(p0: DatabaseError?, p1: Boolean, data: DataSnapshot?) {
                    val listOfObjects = ArrayList()
                    data?.let {
                        data.children.forEach {
                            val child = it.getValue(aClass)
                            child?.let {
                                listOfObjects.add(child)
                            }
                        }
                    }
                    callback.invoke(listOfObjects, true)
                }
    
                override fun doTransaction(p0: MutableData?): Transaction.Result {
                    return Transaction.abort()
                }
            }
    
            val transactionHandlerSuccess = object : Transaction.Handler { //for online load
                override fun onComplete(p0: DatabaseError?, p1: Boolean, data: DataSnapshot?) {
                    countDownTimer?.cancel()
                    val listOfObjects = ArrayList()
                    data?.let {
                        data.children.forEach {
                            val child = it.getValue(aClass)
                            child?.let {
                                listOfObjects.add(child)
                            }
                        }
                    }
                    callback.invoke(listOfObjects, false)
                }
    
                override fun doTransaction(p0: MutableData?): Transaction.Result {
                    return Transaction.success(p0)
                }
            }
    

    In the code if time out is set then I set up timer which will call transaction with abort. This transaction will be called even when offline and will provide online or cached data (in this function there is really high chance that this data is cached one). Then I call transaction with success. OnComplete will be called ONLY if we got response from firebase database. We can now cancel timer (if not null) and send data to callback.

    This implementation makes dev 99% sure that data is from cache or is online one.

    If you want to make it faster for offline (to don't wait stupidly with timeout when obviously database is not connected) then check if database is connected before using function above:

    DatabaseReference connectedRef = FirebaseDatabase.getInstance().getReference(".info/connected");
    connectedRef.addValueEventListener(new ValueEventListener() {
      @Override
      public void onDataChange(DataSnapshot snapshot) {
        boolean connected = snapshot.getValue(Boolean.class);
        if (connected) {
          System.out.println("connected");
        } else {
          System.out.println("not connected");
        }
      }
    
      @Override
      public void onCancelled(DatabaseError error) {
        System.err.println("Listener was cancelled");
      }
    });
    

提交回复
热议问题