<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Jetpack Compose學習(13)——Compose生命周期及副作用函數

      原文: Jetpack Compose學習(13)——Compose生命周期及副作用函數-Stars-One的雜貨小窩

      此文建議需要了解kotlin的lambda表達式使用和協程基礎使用,不然可能會有些閱讀困難

      本篇算是參考他人文章,按照自己理解重新總結了下吧,偏理論

      生命周期

      Composable 組件都是函數,Composable 函數執行會得到一棵視圖樹,每一個 Composable 組件對應視圖樹上的一個節點。

      Composable 的生命周期定義如下:

      • onActive(添加到視圖樹) Composable 首次被執行,即在視圖樹上創建對應的節點。
      • onUpdate(重組) Composable 跟隨重組不斷執行,更新視圖樹上對應的節點。
      • onDispose(從視圖樹移除) Composable 不再被執行,對應節點從視圖樹上移除

      對于 Compose 編寫 UI 來說,頁面的變化,是依靠狀態的變化,Composable 進行重組,渲染出不同的頁面。
      當頁面可見時,對應的節點被添加到視圖樹, 當頁面不可見時,對應的節點從視圖樹移除

      副作用函數

      Composable 重組過程中可能反復執行,并且中間環節有可能被打斷,導致與我們預期次數不符

      比如說:

      在Composable我們有個彈出toast操作,本質上我們是希望它執行一次,但發生重組后,可能會有多次重復執行

      類似這樣,在 Composable 執行過程中,凡是會影響外界的操作,都屬于副作用。

      這個時候,如何保證我們想要的預期執行一次?這個時候就得使用副作用函數來解決此問題,即是下面的內容

      SideEffect

      SideEffect 在每次成功重組的時候都會執行(僅在重組成功才會執行)

      Composable 在重組過程中會反復執行,但是重組不一定每次都會成功,有的可能會被中斷,中途失敗。

      特點:

      1. 重組成功才會執行。
      2. 有可能會執行多次。

      所以,SideEffect函數不能用來執行耗時操作,或者只要求執行一次的操作。

      @Composable
      fun HomePage() {
      	SideEffect{
      		//一些操作
      	}	
      }
      

      DisposableEffect(預處理)

      DisposableEffect 可以感知 Composable 的 onActiveonDispose, 允許使用該函數完成一些預處理和收尾工作。

      DisposableEffect(vararg keys: Any?) {
      	    // register(callback)
      	    onDispose {
      	        // unregister(callback)
      	    }
      	}
      

      這里首先參數 keys 表示,keys可以是任意對象,當 keys 變化時, DisposableEffect 會重新執行,如果在整個生命周期內,只想執行一次,則可以傳入 Unit

      onDispose 代碼塊則會在 Composable 進入 onDispose生命周期 時執行。

      @Composable
      fun HomePage() {
      	DisposableEffect(Unit) {
      	    // register(callback)
      	    onDispose {
      	        // unregister(callback)
      	    }
      	}
      }
      

      LaunchedEffect(比較常用)

      LaunchedEffect 用于在 Composable 中啟動協程,當 Composable 進入 onAtive 時,LaunchedEffect 會自動啟動協程,執行 block 中的代碼。

      當 Composable 進入 onDispose 時,協程會自動取消。

      同樣的,也是有個key參數,變化就會重新執行

      @Composable
      fun HomePage() {
      	//這里我傳了Unit(也是個對象)
      	LaunchedEffect(Unit) {
      	    // do Something async
      	}
      }
      

      rememberCoroutineScope

      LaunchedEffect只能在@Composable函數作用域使用

      如果想要在onclick等事件進行協程等操作,可以使用此rememberCoroutineScope函數來獲取到協程的scope,如下代碼

      @Composable
      fun HomePage() {
      	val scope = rememberCoroutineScope()
      	Button(onClick = {
      		scope.launch{
      			//相關耗時操作
      		}
      	}){
      		Text("點擊操作")
      	}
      }
      

      rememberUpdatedState

      在不中斷協程的情況下,保證始終能夠獲取到最新的值

      總結使用情景:一般情況下,如果我們的@Composable組件需要接受外部數值,且外部數值在父級別@Composable會有數值的更新操作,且我們還使用了副作用函數(不管是在子還是父)

      那么我們這個@Composable組件最好使用rememberUpdatedState來獲取最新數值

      如下面的FinalChoose組件,是接受一個外部數值,但這個數值又有可能在外部被更改(ChooseHero里的sheshou變量),而且FinalChoose中有副作用函數

      @Composable
      fun ChooseHero() {
          var sheshou by remember {
              mutableStateOf("狄仁杰")
          }
      
          Column {
              Text(text = "預選英雄: $sheshou")
      		//點擊按鈕會修改 sheshou 這個變量
              Button(onClick = {
                  sheshou = "馬可波羅"
              }) {
                  Text(text = "改選:馬可波羅")
              }
      		//這里傳入了一個sheshou變量(但里面有個倒計時)
              FinalChoose(sheshou)
          }
      }
      
      
      @Composable
      fun FinalChoose(hero: String) {
          var tips by remember {
              mutableStateOf("游戲倒計時:10s")
          }
      
      	//如果不用這個,此組件的currentHero只會一致等于hero參數
          val currentHero by rememberUpdatedState(newValue = hero)
      	// val currentHero = hero
      
          LaunchedEffect(key1 = Unit) {
      		repeat(9) {
                  "游戲倒計時:${10-it}s"
                  delay(1000)
              }
              tips = "最終選擇的英雄是:$currentHero"
          }
          Text(text = tips)
      }
      

      更詳細說明可以參考此文Compose:長期副作用 + 智能重組 = 若智?聊聊rememberUpdateState - 掘金

      derivedStateOf

      將其他state派生為新的state,使用此函數可確保僅當計算中使用的狀態之一發生變化時才會進行計算,如下代碼:

      @Composable
      fun HomePage() {
      
          val time by remember { mutableIntStateOf(10) }
      
      	//只要當time變更了,這個newTip數據才會變更
          val newTip by remember { derivedStateOf{"剩余時間:$time"} }
      	
      }
      

      produceState

      定義了一個狀態 State, 然后啟動了一個協程,在協程中去更新 State 的值。參數 key 發生變化時,協程會取消,然后重新啟動,生成新的 State。

      將任意數據源轉為state對象(實際我們的操作就是在協程作用域里進行的),如下面代碼

      //這里弄的簡單些,返回個字符串
      val newData by produceState("無數據"){
      	//當前已經在協程作用域里,可以按照需求啟動新協程
      	this.launch {
      		
      	}
      	
      	//異步等操作
      	
      	//模擬請求api數據
      	val result = "數據: {code:200}"
      	delay(500)
      	//設置數據
      	value = result
      	
      	awaitDispose {
      		//一些收尾工作,釋放資源之類會取消觀察
      	}
      }
      

      或者整成個方法來進行調用,如API請求之類:

      @Composable
      fun GetApi(url: String): Recomposer.State<Result<Data>> {
      	//這里produceState傳的url就相當于是key
          return produceState(initialValue = "無數據", url) {
      		//模擬請求api數據
      		val result = "數據: {code:200}"
      		delay(500)
      		//設置數據
      		value = result
      		
              awaitDispose {
              	//一些收尾工作
              }
          }
      }
      

      進階理解 - 穩定和不穩定

      當實體類里存在var關鍵字的成員變量,編譯器寧愿犧牲性能進行一次重組,也不會展示錯的UI

      用 var 聲明 Hero 類的屬性時,Hero 類被 Compose 編譯器認為是不穩定類型:

      • 即有可能,我們傳入的參數引用沒有變化,但是屬性被修改過了,而 UI 又確實需要顯示修改后的最新值。
      • 而當用 val 聲明屬性了,Compose 編譯器認為該對象,只要對象引用不要變,那么這個對象就不會發生變化,自然 UI 也就不會發生變化,所以就跳過了這次重組。

      常用的基本數據類型以及函數類型(lambda)都可以稱得上是穩定類型,它們都不可變

      反之,如果狀態是可變的,那么比較 equals 結果將不再可信。在遇到不穩定類型時,Compose 的抉擇是寧愿犧牲一些性能,也總好過顯示錯誤的 UI。

      如下面的例子:

      //注意參數里有個var
      data class Hero(var name: String,val age:Int=18)
      
      val shangDan = Hero("呂布")
      
      @Composable
      fun StableTest() {
          var greeting by remember {
              mutableStateOf("hello, 魯班")
          }
      
          Column {
              
              Text(text = greeting)
              Button(onClick = {
                  greeting = "hello, 魯班大師"
              }) {
                  Text(text = "搞錯了,是魯班大師")
              }
      		//這里實際上,對象是沒有變的
              ShangDan(shangDan)
          }
      }
      
      @Composable
      fun ShangDan(hero: Hero) {
      	println("執行")
          Text(text = hero.name)
      }
      

      上面的shandan對象是固定的,但是測試,點擊button后,明明沒有更新shandan對象的數值,但發現ShangDan這個組件還是進行了重組操作!

      這個就是因為Hero類中的name為var,被編譯器視為了不穩定,所以犧牲了性能,進行了重組(避免展示了錯誤的UI)

      上面情景中使用var會導致性能會有些損耗,但我們又可能因為業務需求,不能將實體類的成員變量都定為val關鍵字,這個時候還有什么辦法?

      當然有,那就是使用@Stable注解,只要對象引用不變,則不會觸發重組,如下代碼:

      @Stable
      data class Hero(var name: String,val age:Int=18)
      

      參考

      posted @ 2024-08-15 14:27  Stars-one  閱讀(651)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 欧美精品亚洲精品日韩专| 一区二区三区AV波多野结衣| 无码人妻日韩一区日韩二区| 久久精品国产中文字幕| 新婚少妇无套内谢国语播放| 免费观看成人毛片a片| 一本色道久久东京热| 极品美女扒开粉嫩小泬图片| 成人午夜福利视频一区二区| 亚洲高清国产拍精品5G| 亚洲精品日韩在线丰满| 精品国产乱码久久久人妻| 无码熟妇人妻av影音先锋| 老熟妇性老熟妇性色| 亚洲成a人片在线观看中| 青青草国产自产一区二区| 十八岁污网站在线观看| 久久精品国产色蜜蜜麻豆| 日韩精品人妻av一区二区三区| 久久精品国产亚洲αv忘忧草 | 肥西县| 五月天丁香婷婷亚洲欧洲国产| 少妇人妻偷人一区二区| 亚洲精品一品区二品区三品区| 日韩精品一区二区三区激| 国产一区二区日韩经典| 国产自国产自愉自愉免费24区| 呦系列视频一区二区三区| 久久综合九色综合97婷婷| 午夜免费福利小电影| 中文字幕亚洲综合久久| 国产WW久久久久久久久久| 国产精品亚洲二区在线播放| 亚洲av天堂天天天堂色| 乱人伦人妻系列| 极品美女自拍偷精品视频| 亚洲天码中文字幕第一页| 免费看国产曰批40分钟| 亚洲国产大胸一区二区三区| 亚洲色大成网站WWW永久网站| 中文字幕精品亚洲二区|