第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問(wèn)題,去搜搜看,總會(huì)有你想問(wèn)的

為什么調(diào)用 API 或啟動(dòng)協(xié)程的函數(shù)返回空值或空值?

為什么調(diào)用 API 或啟動(dòng)協(xié)程的函數(shù)返回空值或空值?

慕勒3428872 2023-05-10 17:00:15
我試圖從我的一個(gè)操作中獲取數(shù)據(jù),當(dāng)我使用斷點(diǎn)或日志調(diào)試它時(shí),值就在那里,但是當(dāng)我運(yùn)行它時(shí)它們總是空的,我該如何解決這個(gè)問(wèn)題?firebaseFirestore.collection("some collection").get()? ? .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {? ? ? ? @Override? ? ? ? public void onSuccess(QuerySnapshot documentSnapshots) {? ? ? ? ? ? //I want to return these values I receive here...?? ? ? ? });//...and use the returned value here.FacebookGraphRequest request = GraphRequest.newGraphPathRequest(? ? accessToken,? ? "some path",? ? new GraphRequest.Callback() {? ? ? ? @Override? ? ? ? public void onCompleted(GraphResponse response) {? ? ? ? ? ? //I want to return these values I receive here...? ? ? ? }? ? });request.executeAsync();//...and use the returned value here.Kotlin協(xié)程var result: SomeResultType? = nullsomeScope.launch {? ? result = someSuspendFunctionToRetrieveSomething()? ? //I want to return the value I received here...?}Log.d("result", result.toString()) //...but it is still null here.ETC。
查看完整描述

4 回答

?
蠱毒傳說(shuō)

TA貢獻(xiàn)1895條經(jīng)驗(yàn) 獲得超3個(gè)贊

什么是同步/異步操作?


好吧,同步等待直到任務(wù)完成。在這種情況下,您的代碼執(zhí)行“自上而下”。


異步在后臺(tái)完成一個(gè)任務(wù),并且可以在完成時(shí)通知你。


如果你想通過(guò)方法/函數(shù)從異步操作返回值,你可以在你的方法/函數(shù)中定義你自己的回調(diào)來(lái)使用這些操作返回的值。


以下是 Java 的方法


從定義接口開(kāi)始:


interface Callback {

    void myResponseCallback(YourReturnType result);//whatever your return type is: string, integer, etc.

}

接下來(lái),將您的方法簽名更改為如下所示:


public void foo(final Callback callback) { // make your method, which was previously returning something, return void, and add in the new callback interface.

接下來(lái),無(wú)論你以前想使用這些值,添加這一行:


callback.myResponseCallback(yourResponseObject);

舉個(gè)例子 :


@Override

public void onSuccess(QuerySnapshot documentSnapshots) {

    // create your object you want to return here

    String bar = document.get("something").toString();

    callback.myResponseCallback(bar);

})

現(xiàn)在,您之前調(diào)用方法的位置為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 做到這一點(diǎn)? (作為您只關(guān)心單個(gè)結(jié)果的基本示例)


首先將您的方法簽名更改為如下所示:


fun foo(callback:(YourReturnType) -> Unit) {

.....

然后,在異步操作的結(jié)果中:


firestore.collection("something")

         .document("document").get()

         .addOnSuccessListener { 

             val bar = it.get("something").toString()

             callback(bar)

         }

然后,在您之前調(diào)用方法 called 的地方foo,您現(xiàn)在執(zhí)行以下操作:


foo() { result->

    // here, this result parameter that comes through is 

    // whatever you passed to the callback in the code aboce, 

    // so use this result right here to do any operation 

    // you previously wanted to do. 

}

// Be aware that code outside the callback here will run

// BEFORE the code above, and cannot rely on any data that may

// be set inside the callback.

如果您的foo方法之前接受了參數(shù):


fun foo(value:SomeType, callback:(YourType) -> Unit)

您只需將其更改為:


foo(yourValueHere) { result ->

    // here, this result parameter that comes through is 

    // whatever you passed to the callback in the code aboce, 

    // so use this result right here to do any operation 

    // you previously wanted to do. 

}

這些解決方案展示了如何創(chuàng)建一個(gè)方法/函數(shù)來(lái)從您通過(guò)使用回調(diào)執(zhí)行的異步操作中返回值。


但是,重要的是要理解,如果您對(duì)為這些創(chuàng)建方法/函數(shù)不感興趣:


@Override

public void onSuccess(SomeApiObjectType someApiResult) {

    // here, this `onSuccess` callback provided by the api 

    // already has the data you're looking for (in this example, 

    // that data would be `someApiResult`).

    // you can simply add all your relevant code which would 

    // be using this result inside this block here, this will 

    // include any manipulation of data, populating adapters, etc. 

    // this is the only place where you will have access to the

    // data returned by the api call, assuming your api follows

    // this pattern

})


查看完整回答
反對(duì) 回復(fù) 2023-05-10
?
紅糖糍粑

TA貢獻(xiàn)1815條經(jīng)驗(yàn) 獲得超6個(gè)贊

我反復(fù)看到這種性質(zhì)的一種特殊模式,我認(rèn)為對(duì)正在發(fā)生的事情進(jìn)行解釋會(huì)有所幫助。該模式是調(diào)用 API 的函數(shù)/方法,將結(jié)果分配給回調(diào)中的變量,并返回該變量。


以下函數(shù)/方法始終返回 null,即使 API 的結(jié)果不為 null。



fun foo(): String? {

? ?var myReturnValue: String? = null

? ?someApi.addOnSuccessListener { result ->

? ? ? ?myReturnValue = result.value

? ?}.execute()

? ?return myReturnValue

}

Kotlin協(xié)程


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;

}

原因是,當(dāng)您將回調(diào)或偵聽(tīng)器傳遞給 API 函數(shù)時(shí),該回調(diào)代碼只會(huì)在未來(lái)某個(gè)時(shí)間運(yùn)行,當(dāng) API 完成其工作時(shí)。通過(guò)將回調(diào)傳遞給 API 函數(shù),您正在排隊(duì)工作,但當(dāng)前函數(shù)(foo()在本例中)在工作開(kāi)始之前和回調(diào)代碼運(yùn)行之前立即返回。


或者在上面的協(xié)程示例中,啟動(dòng)的協(xié)程不太可能在啟動(dòng)它的函數(shù)之前完成。


調(diào)用 API 的函數(shù)無(wú)法返回回調(diào)中返回的結(jié)果(除非它是 Kotlin 協(xié)程掛起函數(shù))。另一個(gè)答案中解釋的解決方案是讓您自己的函數(shù)采用回調(diào)參數(shù)而不返回任何內(nèi)容。


或者,如果您正在使用協(xié)程,則可以暫停函數(shù)而不是啟動(dòng)單獨(dú)的協(xié)程。當(dāng)您有暫停功能時(shí),您必須在代碼中的某處啟動(dòng)協(xié)程并在協(xié)程中處理結(jié)果。通常,您會(huì)在生命周期函數(shù)(如 )onCreate()或 UI 回調(diào)(如 OnClickListener)中啟動(dòng)協(xié)程。


查看完整回答
反對(duì) 回復(fù) 2023-05-10
?
有只小跳蛙

TA貢獻(xiàn)1824條經(jīng)驗(yàn) 獲得超8個(gè)贊

TL;DR您傳遞給這些 API 的代碼(例如在 onSuccessListener 中)是一個(gè)回調(diào),它異步運(yùn)行(不是按照它在您的文件中寫(xiě)入的順序)。它會(huì)在以后的某個(gè)時(shí)候運(yùn)行以“回調(diào)”到您的代碼中。如果不使用協(xié)程來(lái)掛起程序,則無(wú)法“返回”在函數(shù)的回調(diào)中檢索到的數(shù)據(jù)。


什么是回調(diào)?

回調(diào)是您傳遞給某個(gè)第三方庫(kù)的一段代碼,它將在稍后發(fā)生某些事件時(shí)運(yùn)行(例如,當(dāng)它從服務(wù)器獲取數(shù)據(jù)時(shí))。重要的是要記住,回調(diào)不會(huì)按照您編寫(xiě)的順序運(yùn)行——它可能會(huì)在以后很晚的時(shí)候運(yùn)行,可能會(huì)運(yùn)行多次,或者可能根本不會(huì)運(yùn)行。下面的示例回調(diào)將運(yùn)行點(diǎn) A,啟動(dòng)服務(wù)器獲取進(jìn)程,運(yùn)行點(diǎn) C,退出函數(shù),然后在遙遠(yuǎn)的將來(lái)某個(gè)時(shí)間可能會(huì)在檢索數(shù)據(jù)時(shí)運(yùn)行點(diǎn) B。C 點(diǎn)的打印輸出始終為空。


fun getResult() {

? ? // Point A

? ? var r = ""

? ? doc.get().addOnSuccessListener { result ->

? ? ? ?// The code inside the {} here is the "callback"

? ? ? ?// Point B - handle result

? ? ? ?r = result // don't do this!

? ? }

? ? // Point C - r="" still here, point B hasn't run yet

? ? println(r)

}

那么如何從回調(diào)中獲取數(shù)據(jù)呢?

制作自己的界面/回調(diào)


制作您自己的自定義界面/回調(diào)有時(shí)可以使事情看起來(lái)更清晰,但它并不能真正幫助解決如何在回調(diào)之外使用數(shù)據(jù)的核心問(wèn)題——它只是將 aysnc 調(diào)用移動(dòng)到另一個(gè)位置。如果主要 API 調(diào)用在其他地方(例如在另一個(gè)類(lèi)中),它會(huì)有所幫助。


// you made your own callback to use in the

// async API

fun getResultImpl(callback: (String)->Unit) {

? ? doc.get().addOnSuccessListener { result ->

? ? ? ? callback(result)

? ? }

}


// but if you use it like this, you still have

// the EXACT same problem as before - the printout?

// will always be empty

fun getResult() {

? ? var r = ""

? ? getResultImpl { result ->

? ? ? ? // this part is STILL an async callback,

? ? ? ? // and runs later in the future

? ? ? ? r = result

? ? }

? ? println(r) // always empty here

}


// you still have to do things INSIDE the callback,

// you could move getResultImpl to another class now,

// but still have the same potential pitfalls as before

fun getResult() {

? ? getResultImpl { result ->

? ? ? ? println(result)

? ? }

}

如何正確使用自定義回調(diào)的一些示例:示例 1、示例 2、示例 3

使回調(diào)成為掛起函數(shù)

另一種選擇是使用協(xié)程將異步方法轉(zhuǎn)換為掛起函數(shù),以便它可以等待回調(diào)完成。這使您可以再次編寫(xiě)線性函數(shù)。

suspend fun getResult() {

? ? val result = suspendCoroutine { cont ->

? ? ? ? doc.get().addOnSuccessListener { result ->

? ? ? ? ? ? cont.resume(result)

? ? ? ? }

? ? }

? ? // the first line will suspend the coroutine and wait

? ? // until the async method returns a result. If the?

? ? // callback could be called multiple times this may not

? ? // be the best pattern to use

? ? println(result)

}

將您的程序重新安排為更小的功能


與其編寫(xiě)單一的線性函數(shù),不如將工作分解為幾個(gè)函數(shù)并從回調(diào)中調(diào)用它們。您不應(yīng)嘗試在回調(diào)中修改局部變量并在回調(diào)后返回或使用它們(例如 C 點(diǎn))。當(dāng)數(shù)據(jù)來(lái)自異步 API 時(shí),您必須放棄從函數(shù)返回?cái)?shù)據(jù)的想法——如果沒(méi)有協(xié)程,這通常是不可能的。


例如,您可以在單獨(dú)的方法(一種“處理方法”)中處理異步數(shù)據(jù),并盡可能少地在回調(diào)本身中執(zhí)行操作,而不是使用接收到的結(jié)果調(diào)用處理方法。這有助于避免異步 API 的許多常見(jiàn)錯(cuò)誤,在這些錯(cuò)誤中,您嘗試修改在回調(diào)范圍外聲明的局部變量或嘗試返回從回調(diào)內(nèi)修改的內(nèi)容。當(dāng)您調(diào)用它時(shí)getResult,它開(kāi)始獲取數(shù)據(jù)的過(guò)程。當(dāng)該過(guò)程完成時(shí)(在將來(lái)的某個(gè)時(shí)間)回調(diào)調(diào)用showResult以顯示它。


fun getResult() {

? ?doc.get().addOnSuccessListener { result ->

? ? ? showResult(result)

? ?}

? ?// don't try to show or return the result here!

}


fun showResult(result: String) {

? ? println(result)

}

例子

作為一個(gè)具體示例,這里是一個(gè)最小的 ViewModel,展示了如何將異步 API 包含到程序流中以獲取數(shù)據(jù)、處理數(shù)據(jù)并將其顯示在 Activity 或 Fragment 中。這是用 Kotlin 編寫(xiě)的,但同樣適用于 Java。


class MainViewModel : ViewModel() {

? ? private val textLiveData = MutableLiveData<String>()

? ? val text: LiveData<String>

? ? ? ? get() = textLiveData


? ? fun fetchData() {

? ? ? ? // Use a coroutine here to make a dummy async call,

? ? ? ? // this is where you could call Firestore or other API

? ? ? ? // Note that this method does not _return_ the requested data!

? ? ? ? viewModelScope.launch {

? ? ? ? ? ? delay(3000)

? ? ? ? ? ? // pretend this is a slow network call, this part

? ? ? ? ? ? // won't run until 3000 ms later

? ? ? ? ? ? val t = Calendar.getInstance().time

? ? ? ? ? ? processData(t.toString())

? ? ? ? }


? ? ? ? // anything out here will run immediately, it will not

? ? ? ? // wait for the "slow" code above to run first

? ? }


? ? private fun processData(d: String) {

? ? ? ? // Once you get the data you may want to modify it before displaying it.

? ? ? ? val p = "The time is $d"

? ? ? ? textLiveData.postValue(p)

? ? }

}

一個(gè)真正的 API 調(diào)用fetchData()可能看起來(lái)更像這樣


fun fetchData() {

? ? firestoreDB.collection("data")

? ? ? ? ? ? ? ?.document("mydoc")

? ? ? ? ? ? ? ?.get()

? ? ? ? ? ? ? ?.addOnCompleteListener { task ->

? ? ? ? ? ? ? ? ? ?if (task.isSuccessful) {

? ? ? ? ? ? ? ? ? ? ? ?val data = task.result.data

? ? ? ? ? ? ? ? ? ? ? ?processData(data["time"])

? ? ? ? ? ? ? ? ? ?}

? ? ? ? ? ? ? ? ? ?else {

? ? ? ? ? ? ? ? ? ? ? ?textLiveData.postValue("ERROR")

? ? ? ? ? ? ? ? ? ?}

? ? ? ? ? ? ? ?}

}

隨之而來(lái)的 Activity 或 Fragment 不需要知道這些調(diào)用的任何信息,它只是通過(guò)調(diào)用 ViewModel 上的方法傳遞操作,并觀察 LiveData 以在新數(shù)據(jù)可用時(shí)更新其視圖。它不能假定數(shù)據(jù)在調(diào)用 后立即可用fetchData(),但使用此模式則不需要。


視圖層還可以在加載數(shù)據(jù)時(shí)顯示和隱藏進(jìn)度條,以便用戶知道它正在后臺(tái)工作。


class MainActivity : AppCompatActivity() {

? ? override fun onCreate(savedInstanceState: Bundle?) {

? ? ? ? super.onCreate(savedInstanceState)

? ? ? ? val binding = ActivityMainBinding.inflate(layoutInflater)

? ? ? ? setContentView(binding.root)


? ? ? ? val model: MainViewModel by viewModels()


? ? ? ? // Observe the LiveData and when it changes, update the

? ? ? ? // state of the Views

? ? ? ? model.text.observe(this) { processedData ->

? ? ? ? ? ? binding.text.text = processedData?

? ? ? ? ? ? binding.progress.visibility = View.GONE

? ? ? ? }


? ? ? ? // When the user clicks the button, pass that action to the

? ? ? ? // ViewModel by calling "fetchData()"

? ? ? ? binding.getText.setOnClickListener {

? ? ? ? ? ? binding.progress.visibility = View.VISIBLE

? ? ? ? ? ? model.fetchData()

? ? ? ? }


? ? ? ? binding.progress.visibility = View.GONE

? ? }

}

ViewModel 對(duì)于這種類(lèi)型的異步工作流來(lái)說(shuō)并不是絕對(duì)必要的——這里是一個(gè)如何在活動(dòng)中做同樣事情的例子


class MainActivity : AppCompatActivity() {


? ? private lateinit var binding: ActivityMainBinding


? ? override fun onCreate(savedInstanceState: Bundle?) {

? ? ? ? super.onCreate(savedInstanceState)

? ? ? ? binding = ActivityMainBinding.inflate(layoutInflater)

? ? ? ? setContentView(binding.root)


? ? ? ? // When the user clicks the button, trigger the async

? ? ? ? // data call

? ? ? ? binding.getText.setOnClickListener {

? ? ? ? ? ? binding.progress.visibility = View.VISIBLE

? ? ? ? ? ? fetchData()

? ? ? ? }


? ? ? ? binding.progress.visibility = View.GONE

? ? }

? ??

? ? private fun fetchData() {

? ? ? ? lifecycleScope.launch {

? ? ? ? ? ? delay(3000)

? ? ? ? ? ? val t = Calendar.getInstance().time

? ? ? ? ? ? processData(t.toString())

? ? ? ? }

? ? }

? ??

? ? private fun processData(d: String) {

? ? ? ? binding.progress.visibility = View.GONE

? ? ? ? val p = "The time is $d"

? ? ? ? binding.text.text = p

? ? }

}


(以及,為了完整起見(jiàn),活動(dòng) XML)


<?xml version="1.0" encoding="utf-8"?>

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"

? ? xmlns:app="http://schemas.android.com/apk/res-auto"

? ? xmlns:tools="http://schemas.android.com/tools"

? ? android:layout_width="match_parent"

? ? android:layout_height="match_parent"

? ? tools:context=".MainActivity">


? ? <TextView

? ? ? ? android:id="@+id/text"

? ? ? ? android:layout_margin="16dp"

? ? ? ? android:layout_width="wrap_content"

? ? ? ? android:layout_height="wrap_content"

? ? ? ? app:layout_constraintLeft_toLeftOf="parent"

? ? ? ? app:layout_constraintRight_toRightOf="parent"

? ? ? ? app:layout_constraintTop_toTopOf="parent"/>


? ? <Button

? ? ? ? android:id="@+id/get_text"

? ? ? ? android:layout_width="wrap_content"

? ? ? ? android:layout_height="wrap_content"

? ? ? ? android:layout_margin="16dp"

? ? ? ? android:text="Get Text"

? ? ? ? app:layout_constraintLeft_toLeftOf="parent"

? ? ? ? app:layout_constraintRight_toRightOf="parent"

? ? ? ? app:layout_constraintTop_toBottomOf="@+id/text"

? ? ? ? />


? ? <ProgressBar

? ? ? ? android:id="@+id/progress"

? ? ? ? android:layout_width="match_parent"

? ? ? ? android:layout_height="wrap_content"

? ? ? ? android:padding="48dp"

? ? ? ? app:layout_constraintLeft_toLeftOf="parent"

? ? ? ? app:layout_constraintRight_toRightOf="parent"

? ? ? ? app:layout_constraintTop_toBottomOf="@+id/get_text"

? ? ? ? />


</androidx.constraintlayout.widget.ConstraintLayout>


查看完整回答
反對(duì) 回復(fù) 2023-05-10
?
墨色風(fēng)雨

TA貢獻(xiàn)1853條經(jīng)驗(yàn) 獲得超6個(gè)贊

其他答案解釋了如何通過(guò)在外部函數(shù)中公開(kāi)類(lèi)似的基于回調(diào)的 API 來(lái)使用基于回調(diào)的 API。然而,最近 Kotlin 協(xié)程變得越來(lái)越流行,尤其是在 Android 上,并且在使用它們時(shí),通常不鼓勵(lì)為此目的使用回調(diào)。Kotlin 的方法是改用掛起函數(shù)。因此,如果我們的應(yīng)用程序已經(jīng)使用協(xié)程,我建議不要將回調(diào) API 從 3rd 方庫(kù)傳播到我們的其余代碼,而是將它們轉(zhuǎn)換為掛起函數(shù)。


將回調(diào)轉(zhuǎn)換為掛起


假設(shè)我們有這個(gè)回調(diào) API:


interface Service {

? ? fun getData(callback: Callback<String>)

}


interface Callback<in T> {

? ? fun onSuccess(value: T)

? ? fun onFailure(throwable: Throwable)

}

我們可以使用suspendCoroutine()將其轉(zhuǎn)換為掛起函數(shù):


private val service: Service


suspend fun getData(): String {

? ? return suspendCoroutine { cont ->

? ? ? ? service.getData(object : Callback<String> {

? ? ? ? ? ? override fun onSuccess(value: String) {

? ? ? ? ? ? ? ? cont.resume(value)

? ? ? ? ? ? }


? ? ? ? ? ? override fun onFailure(throwable: Throwable) {

? ? ? ? ? ? ? ? cont.resumeWithException(throwable)

? ? ? ? ? ? }

? ? ? ? })

? ? }

}

這種方式getData()可以直接同步返回?cái)?shù)據(jù),所以其他suspend函數(shù)可以很方便的使用:


suspend fun otherFunction() {

? ? val data = getData()

? ? println(data)

}

請(qǐng)注意,我們不必withContext(Dispatchers.IO) { ... }在這里使用。getData()只要我們?cè)趨f(xié)程上下文中(例如 inside ) ,我們甚至可以從主線程調(diào)用Dispatchers.Main- 主線程不會(huì)被阻塞。


取消


如果回調(diào)服務(wù)支持取消后臺(tái)任務(wù),那么最好在調(diào)用協(xié)程本身被取消時(shí)取消。讓我們?cè)诨卣{(diào) API 中添加一個(gè)取消功能:


interface Service {

? ? fun getData(callback: Callback<String>): Task

}


interface Task {

? ? fun cancel();

}

現(xiàn)在,Service.getData()返回Task我們可以用來(lái)取消操作的返回值。我們可以像以前一樣消費(fèi)它,但有一些小的變化:


suspend fun getData(): String {

? ? return suspendCancellableCoroutine { cont ->

? ? ? ? val task = service.getData(object : Callback<String> {

? ? ? ? ? ? ...

? ? ? ? })


? ? ? ? cont.invokeOnCancellation {

? ? ? ? ? ? task.cancel()

? ? ? ? }

? ? }

}

我們只需要從切換suspendCoroutine()到suspendCancellableCoroutine()并添加invokeOnCancellation()塊。


使用 Retrofit 的示例


interface GitHubService {

? ? @GET("users/{user}/repos")

? ? fun listRepos(@Path("user") user: String): Call<List<Repo>>

}


suspend fun listRepos(user: String): List<Repo> {

? ? val retrofit = Retrofit.Builder()

? ? ? ? .baseUrl("https://api.github.com/")

? ? ? ? .build()


? ? val service = retrofit.create<GitHubService>()


? ? return suspendCancellableCoroutine { cont ->

? ? ? ? val call = service.listRepos(user)


? ? ? ? call.enqueue(object : Callback<List<Repo>> {

? ? ? ? ? ? override fun onResponse(call: Call<List<Repo>>, response: Response<List<Repo>>) {

? ? ? ? ? ? ? ? if (response.isSuccessful) {

? ? ? ? ? ? ? ? ? ? cont.resume(response.body()!!)

? ? ? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? ? ? // just an example

? ? ? ? ? ? ? ? ? ? cont.resumeWithException(Exception("Received error response: ${response.message()}"))

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }


? ? ? ? ? ? override fun onFailure(call: Call<List<Repo>>, t: Throwable) {

? ? ? ? ? ? ? ? cont.resumeWithException(t)

? ? ? ? ? ? }

? ? ? ? })


? ? ? ? cont.invokeOnCancellation {

? ? ? ? ? ? call.cancel()

? ? ? ? }

? ? }

}


在我們開(kāi)始將回調(diào)轉(zhuǎn)換為掛起函數(shù)之前,有必要檢查一下我們使用的庫(kù)是否已經(jīng)支持掛起函數(shù):本機(jī)或通過(guò)一些擴(kuò)展。許多流行的庫(kù)(如 Retrofit 或 Firebase)都支持協(xié)程和掛起函數(shù)。通常,它們要么直接提供/處理掛起函數(shù),要么在異步任務(wù)/調(diào)用/等之上提供可掛起的等待。目的。這種等待經(jīng)常被命名為await()。


比如Retrofit從2.6.0開(kāi)始直接支持suspend函數(shù):


interface GitHubService {

? ? @GET("users/{user}/repos")

? ? suspend fun listRepos(@Path("user") user: String): List<Repo>

}

請(qǐng)注意,我們不僅添加了suspend,而且我們不再返回Call,而是直接返回結(jié)果?,F(xiàn)在,我們可以在沒(méi)有所有這些enqueue()樣板的情況下使用它:


val repos = service.listRepos(user)


查看完整回答
反對(duì) 回復(fù) 2023-05-10
  • 4 回答
  • 0 關(guān)注
  • 244 瀏覽
慕課專(zhuān)欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)