条件"listenerReg != null"在尝试分离/关闭 Firestore 快照时始终为"true" (Android)



上下文:这是我在Android中的第一个项目,我正在问一些愚蠢的问题,但我找不到任何方向(当然,我用Android/Kotlin搞砸了一些关于Angular/Srping的先前知识(

目标:Android 应用将从某些后端微服务获取 Firestore 自定义令牌,然后开始侦听文档。目前为止,一切都好。我阅读了有关如何接近/分离侦听的良好实践,我相信我已经通过将 Android 活动作为快照的第一个参数来成功做到这一点。到目前为止也很好。但就我而言,我必须在 10 分钟后或收到文档中的特定值后关闭/分离快照侦听。现在我真的卡住了。

我尝试了想象中最简单的第一步,我得到了这个话题的天真警告。所以我的问题是:为什么它总是抱怨为真实的条件?来自 Android 专家的补充评论是如何在 10 分钟后关闭/分离快照,以及我是否从收听的文档收到特定值。请接受这两个条件中的任何一个都需要停止侦听并仍然保持相同的 MainActivity.kt 的想法。

这是在onStop循环阶段尝试检查时带有警告的代码

package com.mycomp.appfirestore
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.DocumentSnapshot
import com.google.firebase.firestore.EventListener
import com.google.firebase.firestore.FirebaseFirestore
import com.mycomp.appfirestore.data.service.Endpoint
import com.mycomp.appfirestore.data.service.NetworkUtils
import com.mycomp.appfirestore.model.Transfer
import kotlinx.android.synthetic.main.activity_main.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class MainActivity : AppCompatActivity() {
lateinit var auth: FirebaseAuth
lateinit var listenerReg : FirebaseFirestore
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val btnTransfer = findViewById(R.id.btnTransfer) as Button
val textViewTransfer = findViewById(R.id.textViewTransfer) as TextView
btnTransfer.setOnClickListener {
getToken()
}
}
fun getToken() {
val retrofitClient = NetworkUtils
.getRetrofitInstance("http://192.168.15.13:8080/")
val endpoint = retrofitClient.create(Endpoint::class.java)
...
callback.enqueue(object : Callback<Transfer> {
override fun onFailure(call: Call<Transfer>, t: Throwable) {
Toast.makeText(baseContext, t.message, Toast.LENGTH_SHORT).show()
}
override fun onResponse(call: Call<Transfer>, response: Response<Transfer>) {
listenStatus()
}
})
}
fun listenStatus() {
val TAG = "ListenStatus"
auth = FirebaseAuth.getInstance()
// to make simple for this question let's say the backend returned a valid customtoken used here
auth.signInWithCustomToken("eyJ **** gXsQ")
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
Log.d(TAG, "*** signInWithCustomToken:success")
startSnapshot()
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCustomToken:failure", task.exception)
Toast.makeText(
baseContext, "Authentication failed.",
Toast.LENGTH_SHORT
).show()
}
}
}

fun startSnapshot() {
val TAG = "StartSnapshot"
//Try to pass this(activity context) as first parameter.It will automatically handle acivity life cycle.
// Example if you are calling this listener in onCreate() and passing this as a first parameter then
// it will remove this listener in onDestroy() method of activity.
listenerReg = FirebaseFirestore.getInstance()
listenerReg.collection("transfer")
.document("sDme6IRIi4ezfeyfrU7y")
.addSnapshotListener(
this,
EventListener<DocumentSnapshot?> { snapshot, e ->
if (e != null) {
Log.w(TAG, "Listen failed.", e)
return@EventListener
}
if (snapshot != null && snapshot.exists()) {
textViewTransfer.text = snapshot.data!!["status"].toString()
//Log.d(TAG, snapshot.data!!["status"].toString())
} else {
Log.d(TAG, "Current data: null")
}
})
}
//here I get the warnning mentioned in my question topic
fun stopSnapshot() {
if (listenerReg != null) {
listenerReg.remove()
}
}
}

我知道,由于我很快将活动添加为快照的第一个参数,因此活动将离开,它将自动分离侦听器。但我还有两个条件可以停止倾听:

1 - 10 分钟后

2 - 如果我得到一个特定的返回值

因此,作为虚构的解决方案,我会或多或少地尝试

EventListener<DocumentSnapshot?> { snapshot, e ->
if (e != null) {
Log.w(TAG, "Listen failed.", e)
return@EventListener
}
if (snapshot != null && snapshot.exists()) {
textViewTransfer.text = snapshot.data!!["status"].toString()
**** imagined solution ****
if (snapshot.data!!["status"].toString() == "FINISH"){
stopSnapshot()
}
//Log.d(TAG, snapshot.data!!["status"].toString())
} else {
Log.d(TAG, "Current data: null")
}
})
...
**** imagined solution ***
listenerReg.timeout(10000, stopSnapshot())

要回答您的问题:

为什么它总是抱怨为真实的条件?

您的FirebaseFirestore对象初始化为lateinit var listenerReg : FirebaseFirestore,这意味着您已将listenerReg变量标记为非 null 并稍后初始化。lateinit用于将变量标记为尚未初始化,但基本上承诺在代码中首次引用时将初始化它。如果尝试访问此变量并且未初始化,Kotlin 将在运行时抛出错误。

如果要使其可为空,则需要像这样初始化它:

var listenerReg : FirebaseFirestore? = null

然后,您可以让停止方法如下所示:

fun stopSnapshot() {
if (listenerReg != null) {
listenerReg.remove()
listenerReg.terminate()
listenerRef = null
}
}

但我还有两个条件可以停止倾听: 1 - 10 分钟后

有很多方法可以在Android上设置某些超时。最直接的方法是发布一个将调用stopSnapshot()方法的处理程序,例如:

Handler().postDelayed({
//Do something after 10mins
stopSnapshot();
}, 1000 * 60 * 10)

2 - 如果我得到一个特定的返回值

只需在收到此值时调用stopSnapshot()

注意:我假设所有 Firestore 调用都是正确的。我没有 API 和这种用法。希望我的回答有所帮助。

最新更新