如何使用 Firebase 处理查询中的超时问题



我注意到,如果我在Firebase中执行查询并且数据库服务器无法访问,则回调会永远等待(或直到服务器再次访问)。

如果此行为对于使用的异步方法非常自然,那么使用一种简单的方法来指定超时以便您可以通知用户状态会很有用。

有没有这样的选择,我只是错过了它 - 或者它真的丢失了?或者你会如何解决这个问题?

您可以自己管理一个计时器控制器,该控制器在 x 秒后删除侦听器到您的 Firebase 引用。这很简单,例如安卓中的一行代码。

您可以看到 Web 的代码(分离回调部分):https://www.firebase.com/docs/web/guide/retrieving-data.html

或对于安卓(分离回调部分):https://www.firebase.com/docs/android/guide/retrieving-data.html#section-detaching

IOS ;)的同一部分

根据今天,这些侦听器没有超时概念。一种选择是自己管理超时。

当我还想在加载内容时显示进度对话框时,这就是我的做法。

    private void showProgressDialog(boolean show, long time) {
    try {
        if (progressDialog != null) {
            if (show) {
                progressDialog.setMessage("Cargando...");
                progressDialog.show();
                new Handler().postDelayed(new Runnable() {
                    public void run() {
                        if(progressDialog!=null && progressDialog.isShowing()) {
                            progressDialog.dismiss();
                            Toast.makeText(ActPreguntas.this, "Couldn't connect, please try again later.", Toast.LENGTH_LONG).show();
                        }
                    }
                }, time);
            } else {
                progressDialog.dismiss();
            }
        }
    }catch(IllegalArgumentException e){
    }catch(Exception e){
    }
}

因此,当您向Firebase发出请求时,您可以调用showProgressDialog(true,5000),如果对话框仍然存在,则在5秒后,因为它无法连接,然后您根据超时执行必须执行的操作。

在 Firebase 侦听器的回调中,你执行此 showProgressDialog(false,0)

希望对您有所帮助。

这是我针对Firebase iOS SDK的解决方案,这可能对其他人有所帮助:

extension DatabaseReference {
    func observe(_ eventType: DataEventType, timeout: TimeInterval, with block: @escaping (DataSnapshot?) -> Void) -> UInt {
        var handle: UInt!
        let timer = Timer.scheduledTimer(withTimeInterval: timeout, repeats: false) { (_) in
            self.removeObserver(withHandle: handle)
            block(nil)
        }
        handle = observe(eventType) { (snapshot) in
            timer.invalidate()
            block(snapshot)
        }
        return handle
    }
}

用法:

database.child("users").observe(.value, timeout: 30) { (snapshot) in
    guard let snapshot = snapshot else {
        // Timeout!
        return
    }
    // We got data within the timeout, so do something with snapshot.value
}

我建议简单地使用线程?

允许自己从线程实例中分配对 Firebase 的调用,那么在极少数情况下,写入 Firebase 的时间太长,您可以取消线程吗?

let thread = NSThread(target:self, selector:#selector(uploadToFirebase), object:nil)

func uploadToFirebase(data: Dictionary) {
    // Do what you need to here. Just an example
    db.collection("posts").document("some unique post id").setData([
        "name": "John",
        "likes": 0
    ]) { err in
        if let err = err {
            print("Error writing document: (err)")
        } else {
            print("Document successfully written!")
        }
    }
}

然后只需创建一个计时器,如果计时器触发,该计时器将取消线程。如果没有,只需取消计时器。

如果您使用的是 Firebase SDK v6.5.0 及更高版本,则可以使用 FirebaseOptions 的 setConnectTimeout (https://firebase.google.com/docs/reference/admin/java/reference/com/google/firebase/FirebaseOptions.Builder.html#setConnectTimeout(int))。

样本:

Integer connectTimeoutinMillis = 6000; //6 seconds
FirebaseOptions firebaseOptions = FirebaseOptions.builder()
 .setCredentials(credentials)
 .setDatabaseUrl(Application.firebaseSDKDatabaseUrl)
 .setConnectTimeout(connectTimeoutinMillis)
 .build();
FirebaseApp.initializeApp(firebaseOptions);

最新更新