注册

简单聊聊 compose 的remember

前言


在前面聊mutableStateOf 的时候用了这段代码来讲述了Compose 状态的更新。


code-1
val name = mutableStateOf("hello compose")
setContent {
    Text(name.value)
}

lifecycleScope.launch {
    delay(3000)
    name.value = "android"
}

接下来,我们继续通过这段代码来一起聊下 Composeremember


浅聊


我们先对code-1的代码稍微做下修改


code-2    
    setContent {
            var name by mutableStateOf("hello compose")
            Text(name)
            //ps:此处代码仅做演示使用,compose中协程的使用并非如此
            lifecycleScope.launch {
                delay(3000)
                name = "android"
            }
     }

当我们这样进行修改之后,发现3s过后,“hello compose” 并没有如期变成“android”。


这是为什么呢? 是协程没有执行吗?还是没有进行重组刷新?用最简单的方法,我们来加日志看一下执行。


code-3   
      setContent {
            Log.i("TAG", "setContent: ")
            var name by mutableStateOf("hello compose")
            Text(name)
            //ps:此处代码仅做演示使用,compose中协程的使用会另做讲解。
            lifecycleScope.launch {
                delay(3000)
                name = "android"
                Log.i("TAG", "launch: ")
            }
        }


可以看到,协程已经执行了,而且也进行了重组刷新,但是为什么值没有改变呢?


这是因为使用变量的组件会被包起来,当变量改变的时候会随之进行重组刷新,每次刷新的时候,就会重新创建一个MutableState对象,这个对象就会取默认值“hello compose”。所以才会看起来每次都进行了刷新,但是文字却没有任何改变。



刷新重组的范围就叫做重组作用域。



我们想让Text() 进行刷新怎么办?可以进行包一层。我们对code-2的代码稍微做下修改。


code-4           
setContent {
           var name by mutableStateOf("hello compose")
           Button(onClick = {}){
               Text(name)
           }
            //ps:此处代码仅做演示使用,compose中协程的使用会另做讲解。
            lifecycleScope.launch {
                delay(3000)
                name = "android"
            }
        }

我们让Button 对他进行一个包裹,然后来看看效果。



c490a7f3375d42928186ed8a842aec3f~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.awebp

可以看到进行包裹了之后,文字发生了改变。虽然这样满足了我们的需求,但是不能每次有使用变量的组件,每次都进行一个包裹吧,这岂不是会疯掉。


接下来就需要有请我们今天的主角 remember了,它就是为了帮助我们解决这个问题。


它可以在每次重组的时候,去帮我们去拿已经缓存的值,不需要每次都是重新创建。


code-5             
setContent {
            var name by remember { mutableStateOf("hello compose") }
            Text(name)
            //ps:此处代码仅做演示使用,compose中协程的使用会另做讲解。
            lifecycleScope.launch {
                delay(3000)
                name = "android"
            }
}


abf4b8a663ea483b98aff139ffa30ad8~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.awebp


remember 也是一个Composable 函数,因此只能在Composable 中调用。



现在,我们有个场景,我们需要频繁展示相同的数据,如果使用Text() 直接进行展示,就会每次就会重新计算,但是这些计算没必要的。


为了避免不必要的资源浪费,我们也可以使用remember 来解决。


code-6       
      setContent {
            var name by remember { mutableStateOf("hello compose") }
            ShowCharLenth(name)
            //ps:此处代码仅做演示使用,compose中协程的使用会另做讲解。
            lifecycleScope.launch {
                delay(3000)
                name = "android"
            }
        }

code-7
@Composable
fun ShowCharLenth(value: String) {
    val str = remember { value }
    Text(str)
}

这样使用,就避免了code-7 中的频繁计算重组。


可是这样还会产生一个问题,如果我们展示的数据 如果变了怎么办? 前面的数据进行了缓存,后面的数据即使变了 还会取之前缓存的数据,那直接产生的问题就是数据改变了,但是UI上没有变化。


remember 也早就对这种情况有了解决措施,而且非常简单。


code-8
@Composable
fun ShowCharLenth(value: String) {
    val str = remember(value) { value }
    Text(str)
}

小括号中的value 就是一个key值,根据key值 再去拿remember缓存的数据,这样就完美解决了我们的问题。


至此,我们从这段很短的代码中学到了 remember 的作用 以及使用,感兴趣的同学可以简单上手实践下。


总结


今天的内容就到这里了,非常的简短,主要就是介绍了一下 remember的作用和使用,希望对于新上手Compose的同学有所帮助。


作者:不说话的匹诺槽
链接:https://juejin.cn/post/7194816465290133560
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册