亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何修改函數內的 var 值?

如何修改函數內的 var 值?

紅糖糍粑 2023-05-17 15:53:35
我想設置這個名為 userName 的變量,它應該在 ValueEventListener 中獲得一個新值。但是,在函數內部設置新值時,它不會改變。輸出仍然是“”private fun getName(){    var userName = ""    val user = fbAuth.currentUser    var uid = user!!.uid    mDatabase = FirebaseDatabase.getInstance().getReference("users")    mDatabase.addValueEventListener(object : ValueEventListener {                override fun onCancelled(p0: DatabaseError) {                    TODO("not implemented")                }                override fun onDataChange(snapshot: DataSnapshot) {                    userName = snapshot.child(uid).child("name").getValue().toString()                }    })    println(userName)}預期輸出:John(name child 的值),當前輸出:“”
查看完整描述

3 回答

?
侃侃無極

TA貢獻2051條經驗 獲得超10個贊

監聽器是異步的,如果你把 println 語句放在username =行下面,它就會打印。

事實上,繼續做吧;觀察時間戳;哪個先打???空的還是回調里面的?

var正在被回調修改,但println在 Firebase 發出其值之前很久(在計算機時代,即)首先執行。

此外,我會顛倒行的順序mDatabase。您本質上是在請求一個值,然后聽取結果;結果可能已經發出。您應該先添加偵聽器,然后再請求數據。

更新:如果我需要另一個回調的值怎么辦?

歡迎來到異步編程的世界:-)

你描述的是一組獨立的異步操作。您需要值 A 和值 B,但是在獲得值 A 之前您無法獲得值 B。兩者都是異步的并且需要時間,但是您在主線程上沒有時間,或者更確切地說,您有 ~16ms計算、測量和繪制屏幕,以便操作系統可以保持每秒 60 幀的速度。這不是很多時間,也是異步編程存在的部分原因!

簡而言之,您想要的是一個對象的實例,一旦操作完成就可以調用它。

在常規同步函數中,每個語句都在另一個語句之后執行,并且在前一個語句未完成之前不會執行任何語句;因此,所有語句都是阻塞語句。

例如:

var times = 2

var message = "Hello"

var world = "World"

println("The message is $message $times")

println(world)

將打?。?/p>


The message is Hello 2

World

這是因為執行點會從一行走到另一行,等待上一行執行。如果一個操作需要時間,線程將被阻塞(無法執行任何其他操作)直到該操作完成并且執行點可以移動到下一條指令。


可以想象,iOS 和 Android(以及 Windows、macOS、Linux 等)中的主線程無法被阻止,否則操作系統將無法響應您的觸摸和其他發生的事情(例如,手機,如果用戶界面沒有響應并且您無法點擊“接聽”),則無法處理來電。


這就是為什么我們使用其他“線程”來卸載不是超快的東西。這伴隨著思維方式的改變以及正確的計劃,因為現在事情變得更加復雜了。


讓我們看一個簡單的例子(一些偽代碼,所以請原諒任何明顯的錯誤,這只是為了說明這一點,而不是寫一個解決方案)。


fun main() {

? ? var hello = "Hello"

? ? var message = thisTakesTime()

? ? println("The message is $hello $message")

? ? println(hello)

}


fun thisTakesTime(): String {

? ? // do something that takes 1 second (1000 ms)

? ? Thread.sleep(1000)

? ? return "World"

}

這將打印


The message is Hello World

Hello

如您所見,除了整整一秒鐘,主線程沒有響應外,沒有任何變化。例如,如果您要在 Android 上運行它,它會工作,但您的應用程序在 Thread.sleep 期間不會有一秒鐘的響應。一秒快,試試10秒;在決定需要 ANR(應用程序未響應)對話框之前,這超過了 Android 操作系統對主線程無響應的 5 秒限制;這就是臭名昭著的“看起來 XXX 應用程序沒有響應,等待或關閉”。

你能做什么?

最初,如果你有太多的回調(其中回調 A 在回調 B 完成之前無法執行,而回調 B 在回調 C 完成之前無法執行),并且你開始像那樣嵌套它們,你最終會陷入臭名昭著的回調地獄(在 Javascript) ,但適用于任何語言/平臺)。

基本上跟蹤所有這些異步回調并確保在響應到來時,您的下一個回調已準備就緒,等等是一件痛苦的事情,并且它會引入指數級的復雜性,例如,如果回調 C 在中間失敗,現在您必須讓回調 B 知道 C 失敗了,因此它也必須失敗,這反過來又必須讓回調 A(原來的?。┲?B 失敗了,因此 A 必須對此做些什么,A 是否需要知道 B 因為 C 而失敗了嗎?還是 A 只關心 B 和 B,而 B 失敗背后的原因無關緊要?

好吧,正如您所看到的,即使談論這個也會變得復雜和混亂,我什至沒有涵蓋其他同樣復雜的可能場景。

我在這里想說的并不是說你不應該使用回調;而是說你不應該使用回調。而是您必須仔細計劃何時何地使用它們。

Kotlin 有一些替代方案可以通過使用協程來減少/消除回調地獄,但這些是一個中等高級的主題,它還需要對組件和部件的設計方式進行根本性的改變。

總而言之,對于您的用例,請記住 OOP 的黃金法則:制作做很少事情的小型具體類,并將它們做好。if ()如果您需要在各處開始添加太多,那么您很可能會在各處混合業務邏輯、隨機決策和“whatabout”案例。

假設您有一個處理位置數據并將其上傳到服務器的類。

您可能會想:

  1. 在 Activity/Fragment(或 ViewModel)中編寫所有代碼;很快就變得一團糟。

  2. 使用靜態方法(或單例模式)創建 LocationUtils;已經一團糟,但也很難測試和模擬。如果您需要不止一種類型的處理怎么辦?或者如果你想將它們存儲在數據庫中,你是否要添加更多的靜態方法?

  3. 創建一個小的 LocationProcessor 類,它接收兩個點(緯度/經度)在一個小函數中進行處理,并返回處理后的數據,然后創建另一個名為 LocationUploader 的類,它從處理器接收干凈的輸入,并將其上傳到服務器.?這些類都不應該考慮“如果我沒有權限怎么辦,如果用戶關閉位置怎么辦”等等。這些問題超出了一個類的責任范圍,該類的目的是處理位置坐標,別無其他。應該有其他類負責。請記住,小班級、小職責== 在單個文件中無需擔心。

結論?

好吧,此時有更好的答案可以為您提供所需內容的復制粘貼版本;我相信你今天必須從這堵文字墻中拿出的概念是,為了編寫現代的、可測試的、簡單的功能代碼,你計劃事情的方式必須發生變化。

長話短說:當事情不是同步的時候,你需要保持一些東西(一個對象)準備好被回調(因此名稱回調),監聽(或觀察)(因此我們稱它們為監聽器或觀察器),發射某物(通常稱為 Observable,因為它可以被“觀察”)。

祝你好運!


查看完整回答
反對 回復 2023-05-17
?
慕森卡

TA貢獻1806條經驗 獲得超8個贊

正如 Martin 所說,這是一個異步操作,您應該在異步過程完成后處理文本輸出:


mDatabase.addValueEventListener(object : ValueEventListener {

                override fun onCancelled(p0: DatabaseError) {

                    TODO("not implemented")

                }

                override fun onDataChange(snapshot: DataSnapshot) {

                    userName = snapshot.child(uid).child("name").getValue().toString()

                    println(userName) //--> Asynchronous request has ended, show the name

                }

    })


查看完整回答
反對 回復 2023-05-17
?
哈士奇WWW

TA貢獻1799條經驗 獲得超6個贊

是的,偵聽器是異步的,只有在 onDataChange 方法中打印變量時它才會起作用。


但是,您可以使用回調策略來等待 Firebase 返回數據。是這樣的:


interface MyCallback {

    fun onCallback(value: String )

}


fun readData(myCallback: MyCallback){

    mDatabase.addValueEventListener(object : ValueEventListener {

        override fun onDataChange(snapshot: DataSnapshot) {

            userName = snapshot.child(uid).child("name").getValue().toString()

            myCallback.onCallback(value)

        }

    })

}


fun test(){

    readData(object: MyCallback {    

        override fun onCallback(value : String) {

            println(value)

        }

    })


}


查看完整回答
反對 回復 2023-05-17
  • 3 回答
  • 0 關注
  • 207 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號