(免责声明:人们通过Facebook,firebase等请求使用异步操作时,人们询问数据是否为空/不正确,这引起了很多问题。我想提供一个简单的答案这个问题对所有开始使用android中的异步操作的人来说都是一样,因为我在搜索后无法真正找到一个示例)
我试图从我的一项操作中获取数据,当我调试它时,值就在那里了,但是当我运行它们时它们总是为空,我该如何解决呢?
Firebase
firebaseFirestore.collection("some collection").get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
//I want to get these values here?
})
GraphRequest request = GraphRequest.newGraphPathRequest(
accessToken,
"some path",
new GraphRequest.Callback() {
@Override
public void onCompleted(GraphResponse response) {
//I want to get these values here?
}
});
request.executeAsync();
答案 0 :(得分:9)
什么是同步/异步操作?
好吧,同步一直等到任务完成。在这种情况下,您的代码将“自上而下”执行。
异步在后台完成任务,并在完成时通知您。
要从异步操作中获取值,可以在方法中定义自己的回调以使用这些值,因为这些值是从这些操作返回的。
Java的使用方法
首先定义一个接口:
interface Callback {
void myResponseCallback(YourReturnType result);//whatever your return type is: string, integer, etc.
}
接下来,将您的方法签名更改为:
public void foo(final Callback callback) { // make your method, which was previously returning something, return void, and add in the new callback interface.
接下来,无论您以前想使用这些值的何处,都请添加以下行:
callback.myResponseCallback(yourResponseObject);
例如:
@Override
public void onSuccess(QuerySnapshot documentSnapshots) {
// create your object you want to return here
String bar = document.get("something").toString();
callback.myResponseCallback(bar);
})
现在,您先前在哪里调用了名为foo
的方法:
foo(new Callback() {
@Override
public void myResponseCallback(YourReturnType result) {
//here, this result parameter that comes through is your api call result to use, so use this result right here to do any operation you previously wanted to do.
}
});
}
您如何为Kotlin做到这一点? (作为一个基本示例,其中您只关心单个结果)
首先将您的方法签名更改为以下内容:
fun foo(callback:(YourReturnType) -> Unit) {
.....
然后,在异步操作的结果中:
firestore.collection("something").document("document").get().addOnSuccessListener {
val bar = it.get("something").toString()
callback.invoke(bar)
}
然后,您本来可以在以前调用名为foo
的方法的位置执行此操作:
foo { result->
here, this result parameter that comes through is your api call result to use, so use this result right here to do any operation you previously wanted to do.
}
如果您的foo
方法以前使用了参数:
fun foo(value:SomeType, callback:(YourType) -> Unit)
您只需将其更改为:
foo(yourValueHere) { result ->
here, this result parameter that comes through is your api call result to use, so use this result right here to do any operation you previously wanted to do.
}
答案 1 :(得分:1)
我多次看到这种性质的特殊模式,我认为对正在发生的事情进行解释会有所帮助。该模式是一个函数/方法,它调用 API,将结果分配给回调中的一个变量,然后返回该变量。
以下函数/方法始终返回 null,即使 API 的结果不为 null。
科特林
fun foo(): String? {
var myReturnValue: String? = null
someApi.addOnSuccessListener { result ->
myReturnValue = result.value
}.execute()
return myReturnValue
}
Kotlin 协程
fun foo(): String? {
var myReturnValue: String? = null
lifecycleScope.launch {
myReturnValue = someApiSuspendFunction()
}
return myReturnValue
}
Java 8
private String fooValue = null;
private String foo() {
someApi.addOnSuccessListener(result -> fooValue = result.getValue())
.execute();
return fooValue;
}
Java 7
private String fooValue = null;
private String foo() {
someApi.addOnSuccessListener(new OnSuccessListener<String>() {
public void onSuccess(Result<String> result) {
fooValue = result.getValue();
}
}).execute();
return fooValue;
}
原因是当您将回调或侦听器传递给 API 函数时,该回调代码只会在 API 完成其工作后的某个时间运行。通过将回调传递给 API 函数,您正在排队工作,但当前函数(在本例中为 foo()
)在该工作开始之前和该回调代码运行之前立即返回。
或者在上面的协程示例中,启动的协程不太可能在启动它的函数之前完成。
您调用 API 的函数无法返回回调中返回的结果(除非它是 Kotlin 协程挂起函数)。另一个答案中解释的解决方案是让您自己的函数接受回调参数而不返回任何内容。