当前位置: 首页 > news >正文

鄂州正规网站建设wordpress 快站

鄂州正规网站建设,wordpress 快站,四川省建设厅电子政务网站,东莞原创设计院官网在Android应用中可以通过定义可组合函数来搭建应用界面。应用界面的更新往往是与可组合函数内部定义的状态值相关联的。当界面的状态值发生变更#xff0c;会导致应用界面进行更新。在Android笔记#xff08;九#xff09;#xff1a;Compose组件的状态#xff0c;对Compo…在Android应用中可以通过定义可组合函数来搭建应用界面。应用界面的更新往往是与可组合函数内部定义的状态值相关联的。当界面的状态值发生变更会导致应用界面进行更新。在Android笔记九Compose组件的状态对Compose组件的状态进行详细地介绍。理想状态下可组合函数使用是定义范围内的状态值通过内部状态的变更修改可组合项构成的界面。但是在有些特殊场景下需要在可组合项中运行一些在可组合函数作用域外的一些应用状态。简单地说附带效应就是在可组合函数中一些可组合函数作用域外的应用状态的变化。这些效应在可组合函数范围外对于可组合函数来说并不好控制容易造成过度使用。因此需要结合Effect API来对这些效应进行可预测地控制和处理。 一、什么是附带效应 在前述中对附带效应进行简单说明在下面需要通过应用实例来解释 运行下列代码块 //全局变量在MainScreen作用域外 val timer mutableIntStateOf(0)Composable fun MainScreen(){//函数作用域内var runningState remember{mutableStateOf(false)}val scope rememberCoroutineScope()Box(modifier Modifier.fillMaxSize(),contentAlignment Alignment.Center){Column(modifier Modifier.fillMaxWidth(),horizontalAlignment Alignment.CenterHorizontally,verticalArrangement Arrangement.Center){Text(text 计时器,fontSize30.sp,colorMaterialTheme.colorScheme.primary)Text(text ${timer.value}秒,fontSize 24.sp)Row(modifier Modifier.fillMaxWidth(),horizontalArrangement Arrangement.Center){IconButton(modifier Modifier.width(100.dp),onClick{runningState.value truescope.launch {while(runningState.value){delay(1000)timer.value 1Log.d(TAG,${timer} m)}}}){Row{Icon(imageVector Icons.Filled.Start,tint Color.Green,contentDescription null)Text(计时)}}IconButton(modifier Modifier.width(100.dp),onClick{runningState.value false}){Row{Icon(imageVector Icons.Filled.Stop,tint Color.Green,contentDescription null)Text(计时)}}}}} }在上述代码中有几点需要注意 1.rememberCoroutineScope函数 rememberCoroutineScope函数可以获取感知作用域在可组合项外启动协程。在上述代码中定义的IconButton中的点击事件onClick的处理timerState值的变化。因为下列的代码段 while(runningState.value){ delay(1000) timer.value 1 Log.d(“TAG”,${timer} m) } delay函数是一个挂起函数表示地是在不阻塞线程的情况下将协程延迟给定时间例如代码中设置的1秒并在指定时间后恢复。因此需要在协程的范围中调用delay这个挂起函数因此利用rememberCoroutineScope函数获得一个CorountineScope协程范围在该范围可以对挂起函数进行调用。 val scope rememberCoroutineScope() scope.launch{ while(runningState.value){ delay(1000) timer.value 1 Log.d(“TAG”,${timer} m) } } 2.关于外部量的变化 定义了状态值timerState和MainScreen()这个可组合函数。timerState这个可变的状态值是一个全局量在MainScreen()函数的作用域外。需要将timerState的值进行修改会发生在两种情况 1MainScreen()可组合函数调用时 2MainScreen()函数进行重组时会调用timerState 而在第二种情况中可组合函数重组时所触发timerState状态值的变化而变化的情况就是发生了附带效应。但是上述代码定义的timerState值的变化是不可预知的因为它的作用域在MainScreen函数外外界也有可能存在促使timerState值变化的情况。因此需要一些方法对timerState值的变更情况做出预测并做出相应的处理。 图1 附带效应示意 二、LaunchedEffect LaunchedEffect函数可以在某个可组合项的作用域内运行挂起函数时它会启动内部的代码块到协程上下文CoroutineContext中。当函数的key1的值发生变化会重构LaunchedEffect。这时LaunchedEffect原来启动的协程会被取消然后又重新启动。当LaunchedEffect退出组合项时协程会被取消。LaunchedEffect可组合函数定义如下 Composable NonRestartableComposable OptIn(InternalComposeApi::class) fun LaunchedEffect( key1: Any?, block: suspend CoroutineScope.() - Unit ) { val applyContext currentComposer.applyCoroutineContext remember(key1) { LaunchedEffectImpl(applyContext, block) } } 其中LaunchedEffect函数中的参数 key1表示关键字可以是任何类型如果是可变的状态值时可以根据可变状态值的变化取消原有协程并启动新的协程。 当key1为Unit或true时LaunchedEffect函数将与当前重组函数保持一致的生命周期。 block:表示要调用的挂起函数。需要在协程范围中运行 修改上述计时器的代码段代码如下所示 //全局变量在MainScreen作用域外 val timer mutableIntStateOf(0)Composable fun MainScreen(){//函数作用域内var runningState remember{mutableStateOf(false)}val scope rememberCoroutineScope()LaunchedEffect(key1 timer.value){ //一旦发生修改不断取消原有协程创建新的协程delay(1000)timer.value 1 //会使得LaunchedEffect不断重构}Box(modifier Modifier.fillMaxSize(),contentAlignment Alignment.Center){Column(modifier Modifier.fillMaxWidth(),horizontalAlignment Alignment.CenterHorizontally,verticalArrangement Arrangement.Center){Text(text 计时器,fontSize30.sp,colorMaterialTheme.colorScheme.primary)Text(text ${timer.value}秒,fontSize 24.sp)Row(modifier Modifier.fillMaxWidth(),horizontalArrangement Arrangement.Center){IconButton(modifier Modifier.width(100.dp),onClick{runningState.value truetimer.value 1 //点击按钮控制第一次值的修改}){Row{Icon(imageVector Icons.Filled.Start,tint Color.Green,contentDescription null)Text(计时)}}IconButton(modifier Modifier.width(100.dp),onClick{runningState.value falsetimer.value 1}){Row{Icon(imageVector Icons.Filled.Stop,tint Color.Green,contentDescription null)Text(停止)}}}}} }在上述代码中可以发现当点击计时按钮时修改了LaunchedEffect函数中的键参数timer.value的值使得LaunchedEffect函数timer.value的值的变化使得原有协程取消启动新的协程并在新的协程中修改了timer.value的值LaunchedEffect函数的不断重构使得状态值不断修改导致计时界面MainScreen不断重构和刷新。通过这样的方式达到对timer.value修改的可预测控制。但是这种不断切换协程的方式并不可取可以修改代码成如下的形式 //全局变量在MainScreen作用域外 val timer mutableIntStateOf(0)Composable fun MainScreen(){//函数作用域内var runningState remember{mutableStateOf(false)}val scope rememberCoroutineScope()LaunchedEffect(key1 runningState.value){while(runningState.value){delay(1000)timer.value 1Log.d(TAG,${timer} m)}}Box(modifier Modifier.fillMaxSize(),contentAlignment Alignment.Center){Column(modifier Modifier.fillMaxWidth(),horizontalAlignment Alignment.CenterHorizontally,verticalArrangement Arrangement.Center){Text(text 计时器,fontSize30.sp,colorMaterialTheme.colorScheme.primary)Text(text ${timer.value}秒,fontSize 24.sp)Row(modifier Modifier.fillMaxWidth(),horizontalArrangement Arrangement.Center){IconButton(modifier Modifier.width(100.dp),onClick{runningState.value true}){Row{Icon(imageVector Icons.Filled.Start,tint Color.Green,contentDescription null)Text(计时)}}IconButton(modifier Modifier.width(100.dp),onClick{runningState.value false}){Row{Icon(imageVector Icons.Filled.Stop,tint Color.Green,contentDescription null)Text(停止)}}}}} }运行效果是 在上述代码段中按钮的点击动作只是修改了可组合函数内部的runningState状态值。但是 LaunchedEffect(key1 runningState.value){ scope.launch { while(runningState.value){ delay(1000) timer.value 1 Log.d(“TAG”,${timer} m) } } } 如果点击按钮会修改键参数runingState.value的值。而在上述代码的LaunchedEffect函数中监控到runningState.value值的变化会将原来的协程取消然后再重新启动新的协程在新的协程中修改MainScreen可组合函数外部的timerState状态值从而达到计时的功能实现。在这里是通过控制runningState来达到修改外部timerState的目的。如果runningState.value值没有发生任何变化那么原有的协程不会取消会继续运行。如果runningState.value的值为false那么界面将不会发生变化。通过这样的方式LaunchedEffect监控key1的变化使得对timerState.value修改可以控制。 三、rememberUpdatedState 在上述代码中LaunchedEffect函数会根据关键字的值的变化重启协程。但是在某些情况下并不希望LaunchedEffect重启但是却需要LaunchedEffect函数中变更的状态的值。因此可以考虑使用rememberUpdatedState函数用于创建可捕获和更新该值的引用。但是注意这样的处理方式代价会比较高昂。 //全局变量在MainScreen作用域外 val timer mutableIntStateOf(0)Composable fun MainScreen(){//函数作用域内var runningState remember{mutableStateOf(true)}val scope rememberCoroutineScope()val timerState rememberUpdatedState(newValue timer)LaunchedEffect(Unit){while(runningState.value){delay(1000)timerState.value.value 1Log.d(TAG,${timer.value} m)}}Box(modifier Modifier.fillMaxSize(),contentAlignment Alignment.Center){Column(modifier Modifier.fillMaxWidth(),horizontalAlignment Alignment.CenterHorizontally,verticalArrangement Arrangement.Center){Text(text 计时器,fontSize30.sp,colorMaterialTheme.colorScheme.primary)Text(text ${timerState.value.value}秒,fontSize 24.sp)Row(modifier Modifier.fillMaxWidth(),horizontalArrangement Arrangement.Center){IconButton(modifier Modifier.width(100.dp),onClick{runningState.value true}){Row{Icon(imageVector Icons.Filled.Start,tint Color.Green,contentDescription null)Text(计时)}}IconButton(modifier Modifier.width(100.dp),onClick{runningState.value falsetimer.value 1}){Row{Icon(imageVector Icons.Filled.Stop,tint Color.Green,contentDescription null)Text(停止)}}}}} }在上述代码中MainScreen可组合函数内部定义 val timerState rememberUpdatedState(newValue timer) 而在LaunchedEffect代码部分定义为 LaunchedEffect(Unit){ while(runningState.value){delay(1000)timerState.value.value 1Log.d(TAG,${timer.value} m)}}LaunchedEffect函数中的键参数为Unit这表示在MainScreen函数被调用时或重新组合时才会加载LaunchedEffect函数。并不存在键参数值的变化重新加载协程代码的可能。但是通过rememberUpdatedState(newValue timer)函数一致可以通过timerState.value来获取变化的状态timer. 因此在上述代码中由于runningState.value初始值为true,因此一启动MainScreen就会显示显示动态计时的效果。但是当点击停止按钮runningState.value的值设置为false导致代码段停止运行。然后再点击计时“按钮可以发现LaunchedEffect函数并没有重启。 四、DisposableEffect清理效应 对于需要在键发生变化或可组合项退出组合后进行清理的附带效应可以通过DisposableEffect来实现。DisposableEffect是组合的附效应。DisposableEffect函数定义如下 Composable NonRestartableComposable fun DisposableEffect( key1: Any?, effect: DisposableEffectScope.() - DisposableEffectResult ) { remember(key1) { DisposableEffectImpl(effect) } } 当key1是键参数可以为任何值。当key1的值发生变化或者DisposableEffect离开可组合项则必须执行撤销或清除操作。 //全局变量在MainScreen作用域外 val timer mutableIntStateOf(0)Composable fun MainScreen(){//函数作用域内var runningState remember{mutableStateOf(true)}val scope rememberCoroutineScope()LaunchedEffect(Unit){while(runningState.value){delay(1000)timer.value1Log.d(TAG,${timer.value} m)}}DisposableEffect(key1 timer.value){onDispose {timer.value 0runningState.value false}}Box(modifier Modifier.fillMaxSize(),contentAlignment Alignment.Center){Column(modifier Modifier.fillMaxWidth(),horizontalAlignment Alignment.CenterHorizontally,verticalArrangement Arrangement.Center){Text(text 计时器,fontSize30.sp,colorMaterialTheme.colorScheme.primary)Text(text ${timer.value}秒,fontSize 24.sp)Row(modifier Modifier.fillMaxWidth(),horizontalArrangement Arrangement.Center){IconButton(modifier Modifier.width(100.dp),onClick{runningState.value true}){Row{Icon(imageVector Icons.Filled.Start,tint Color.Green,contentDescription null)Text(计时)}}IconButton(modifier Modifier.width(100.dp),onClick{runningState.value falsetimer.value 1}){Row{Icon(imageVector Icons.Filled.Stop,tint Color.Green,contentDescription null)Text(停止)}}}}} }上述代码的界面没有任何变化这是因为下列代码 LaunchedEffect(Unit){ scope.launch { while(runningState.value){ delay(1000) timer.value1 Log.d(“TAG”,${timer.value} m) } } } DisposableEffect(key1 timer.value){onDispose {timer.value 0runningState.value false} }启动MainScreen时timer.value修改为1但是DisposableEffect发现到timer.value变更就会执行清除操作修改timer.value0和runningState.valuefalse。在后续中将无法动态显示计时效果。DisposableEffect往往和生命周期进行关联当键参数为生命周期拥有者对象时可以利用DisposableEffect对生命周期拥有者的变化执行撤销或清理的工作。 在下面定义两个活动MainActivity和OtherActivity这两个活动分别为不同的生命周期拥有者具有不同的生命周期对象。具体定义如下 1MainActivity的定义 首先定义依附MainActivity的界面HomeScreen的定义 Composable fun HomeScreen(lifecycleOwner:LifecycleOwner LocalLifecycleOwner.current,onStart:(MutableStateInt)-Unit,onStop:(MutableStateInt)-Unit){val startAction by rememberUpdatedState(newValue onStart)val stopAction by rememberUpdatedState(newValue onStop)val context LocalContext.currentvar timer remember{mutableIntStateOf(0)}//以键参数为生命周期拥有者lifecycleOwnerDisposableEffect(key1 lifecycleOwner){//定义生命周期观察者val observer LifecycleEventObserver{_,event-if(event Lifecycle.Event.ON_RESUME){startAction(timer)}else if(event Lifecycle.Event.ON_STOP){stopAction(timer)}}//生命周期拥有者lifecycleOwner的生命周期lifecycle加入新的观察者observer观察者可以观察生命周期的变化lifecycleOwner.lifecycle.addObserver(observer)onDispose {//当离开可组合项执行清理处理Log.d(TAG,清理完毕)timer.value 0lifecycleOwner.lifecycle.removeObserver(observer)}}Box(contentAlignment Alignment.Center,modifier Modifier.fillMaxSize()){Column{Text(text ${timer.value}秒,fontSize30.sp)Button(onClick {//跳转到其他活动即修改了生命周期拥有者对象val intent Intent(context, OtherActivity::class.java)context.startActivity(intent)}){Text(跳转到其他活动)}}} }再定义主活动MainActivity class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {Ch06_DemoTheme {// A surface container using the background color from the themeSurface(modifier Modifier.fillMaxSize(),color MaterialTheme.colorScheme.background) {HomeScreen(onStart ::onStartCall, onStop ::onStopCall )}}}}fun onStartCall(timer: MutableStateInt){Log.d(TAG,startCall)thread{while(timer.value100){timer.valueThread.sleep(1000)}}}fun onStopCall(timer: MutableStateInt){//start停止Log.d(TAG,stopCall)} }2OtherActivity的定义 class OtherActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent{Box(contentAlignment Alignment.Center,modifier Modifier.wrapContentSize()){Text(OtherActivity,fontSize 30.sp)}}} }运行情况说明 1点击运行的效果如下图所示 2当点击”跳转其他活动“按钮跳转到OtherActivity的界面跟踪的日志如下 日志显示 3当彻底退出关闭这个应用则在日志中显示 这是因为在跳转到OtherActivity时LifecycleOwner虽然已经切换到OtherActivity但是界面HomeScreen已经在后台因此并没有执行onDispose的代码块。只有在彻底退出应用彻底离开可组合函数HomeScreen可组合函数HomeScreen中的DisposableEffect中监测到代码生命周期拥有者的对象发生了变化因此执行onDispose代码块。 五、SideEffect 可组合函数进行重组时并不是每次都成功如果出现界面状态值发生变化但是界面会进行重组。但是在重组的过程中一些状态数据又发生了变化导致上次重组没有完全完成。这就使得一些与界面重组无关的数据和代码也会被多次调用这种情况显然是没有必要的。在这样的前提下可以使用SideEfffect。 SideEffect表示“副作用”,它将 Compose 的状态发布为非 Compose 代码。如需与非 Compose 管理的对象共享 Compose 状态可使用 SideEffect 中可组合项因为只有每次成功重组时才会调用该可组合项。 SideEffect函数定义如下 Composable NonRestartableComposable OptIn(InternalComposeApi::class) fun SideEffect(effect: () - Unit ) { currentComposer.recordSideEffect(effect) } 观察下列代码运行结果和日志 Preview Composable fun SideScreen(){//可组合的状态var timer by remember{ mutableIntStateOf(0) }var running by remember{mutableStateOf(false)}Log.d(TAG,在SideEffect前的日志)SideEffect{Log.d(TAG,执行SideEffect函数:running:${running})if(running) {timerThread.sleep(1000)}}Log.d(TAG,在SideEffect函数后的日志)Box(contentAlignment Alignment.Center,modifier Modifier.fillMaxSize()){Column{Text(text ${timer}秒,fontSize30.sp)Row(horizontalArrangement Arrangement.Center){Button(onClick {running trueLog.d(TAG,running:${running})}){Text(计时)}Button(onClick {running falsetimer 0Log.d(TAG,running:${running})}){Text(停止)}}}} }上述代码的运行结果如下所示 并没有发生动态更新计时时间的显示。这是因为running的值为false在条件判断时使得timer状态值无法发生变化状态值没有变化使得界面只会在调用时刷新界面。即使点击”计时“按钮修改了running的值为true,因为影响界面重组的状态值timer并没有变化因此界面没有发生重组。这与日志显示是一致的。下图显示的日志就是这样的效果。 观察日志可以发现调用可组合函数SideScreen时重组成功后才会调用SideEffect函数。因为日志输出SideEffect函数内部的Lambda代码段中的日志是最后调用的。 再来观察下列代码 1定义数据类Timer /*** counter:Int记录已经计时的时间* timerInterval:Int时间间隔* / data class Timer(var counter:Int,val timeInterval:Int1000)2定义将Compose状态返回非Compose的值 Composable fun rememberTimer(counter:Int):Timer{//定义可组合的对象val timer remember{Timer(0)}SideEffect{timer.counter counter}return timer }在上述的可组合函数rememberTimer中生成并返回了一个非Compose的Timer对象 3在界面中进行测试 Preview Composable fun SideScreen(){//非状态的对象var timer rememberTimer(counter 0)val scope rememberCoroutineScope()var running by remember{mutableStateOf(true)}Box(contentAlignment Alignment.Center,modifier Modifier.fillMaxSize()){Column{Text(text ${timer.counter}秒,fontSize30.sp)Row(horizontalArrangement Arrangement.Center){Button(onClick {running truescope.launch {while(running){delay(1000)timer.counterLog.d(TAG,timer.counter)}}Log.d(TAG,running:${running})}){Text(计时)}Button(onClick {running falsetimer.counter 0Log.d(TAG,running:${running})}){Text(停止)}}}} }运行效果如上图一致。 执行点击”计时“按钮即使running的值为true界面不会重组。这是因为影响界面的timer已经是一个非Compose的对象并不能对界面的重组起到作用。观察日志可以发现timer.counter值的确每秒进行变更了。 参考文献 1.Compose 中的附带效应 https://developer.android.google.cn/jetpack/compose/side-effects?hlzh-cn
http://www.huolong8.cn/news/117921/

相关文章:

  • 公司网站建设实施方案宁波江北建设局网站
  • ppt做网站安康微平台
  • 淘宝客网站还可以做吗网站开发技术简介
  • 可以自己做头像的网站重庆建设施工安全信息网官网
  • 深圳建站公司外围域名备案要求
  • 北京医疗网站建设公司网站 建设服务器
  • 风险的网站怎么出现cn网站
  • 帝国cms企业网站网站建立方案
  • 淘宝网怎样做网站代还app开发公司
  • 电商网站 网站服务内容富阳网站定制开发哪家公司好
  • 自己做网站需要学什么东西做电商网站商标
  • html5自适应网站模版淄博网站定制
  • 南京网站设计费用四川城乡和住房建设厅官方网站
  • 国外代码开源网站ps做好的网站如何做链接
  • 公司网站发布流程网站建设与小程序开发熊掌号
  • 龙华做网站怎么样对运营网站有什么见解
  • 网站建设技术概述合肥优化推广公司
  • 部门网站建设整改网站维护是什么
  • 网站添加内容WordPress添加在线商店
  • 创意工作室网站郑州网站建设专注乐云seo
  • 坑梓网站建设市场执业医师报考条件2022年最新规定
  • 上海专业网站建设公司排名如何选择网站的关键词
  • 哪里有免费网站空间申请潍坊网站建设尚荣
  • 沈阳做网站哪家质量好价格低长清区seo网络优化软件
  • 网站架构组成部分公司做网站哪里好
  • 外贸建站与推广如何做宁金诚信建设网站
  • 基于php的网站设计与实现山东前十名建筑设计院
  • 网站制作公司咨询网站制作公司山西长治做网站公司有哪些
  • 网站开发的8个步骤门户网站类型有哪些
  • 深圳 网站设计师 招聘建设资格执业注册中心网站