JetPack重新组成的常见问题
#kotlin #android #jetpackcompose

recomposição是JetPack组成功能的基本步骤。如果您不知道它是什么,基本上,它是通过应用状态更新重新设计屏幕的阶段。

换句话说,每次我们在屏幕上都有一些新的东西,无论是文本字段,动物,颜色变化等的编辑。

每次发生koude0更新时都会发生建议,或更准确,源自State并允许更新值发生重新组件的Abiaqian2。 /p>

尽管看起来很简单,但是在使用此行为开发应用程序时,我们需要小心避免某些陷阱,无论是不必要的,甚至是无限的循环!

要进行简单的演示,我们可以添加一名会计师并在屏幕上显示:

var counter = 0

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            PlaygroundTheme {
                Surface(
                    Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background,
                ) {
                    var text by remember {
                        mutableStateOf("")
                    }
                    Column {
                        Text(text = "${counter++}")
                        TextField(value = text, onValueChange = {
                            text = it
                        })
                    }
                }
            }
        }
    }

}

App em execução apresentado um texto com um contador iniciando em zero e um campo de texto com o texto vazio. Ao digitar ou apagar texto do campo de texto, o contador é incrementado

请参阅仅写“ Alex Felipe”并删除所有字母,有22个重新组件!

尽管它有很大的数量,但通常会发生更多的重新组件,毕竟,屏幕可以执行多个更新,具有动物,懒惰的结构等。

但是,有比我们应有的重新组成!让我们开始探索一点,例如试图寻求信息并在组成中更新状态。

模拟不必要的重新分配

为了举例说明,我将创建一种模拟所有常规搜索的方式:

class User(
    val id: Long,
    val name: String
)

fun findAllUsers() = flow {
    delay(Random.nextLong(100, 500))
    emit(listOf(User(1, "alex")))
}

即使是一种返回“享受列表”的方式(每次创建新列表的细化时),也是一个非常有趣的情况,可以观察到重新分配不必要!

delay()的周期为100至500毫秒,是在测试过程中促进结果的视图。 Engy,在组合中,我们可以提出列表的竞赛:

val users by findAllUsers().collectAsState(initial = emptyList())
Column {
    Text(text = "${counter++}")
    for (user in users) {
        Column {
            Text(text = user.id.toString())
            Text(text = user.name)
        }
    }
}

App em execução apresentando o contador zerado inicialmente. Após instantes, aparece um usuário abaixo com id e nome, e então, o contador é incrementado automaticamente em períodos diferentes

一个好奇的结果...您同意吗?尽管屏幕“没有添加新的常规”,但重新组件的发生通常是徒劳的,通常趋向于无穷大...

了解陷阱的危险

重要的是要注意,这是一个受到一定延迟的受控实现,但现在可以想象,在情况下,搜索信息来自消耗设备,Internet等功能的集成。

我们将创建一个效率低下的解决方案,以损害应用程序的质量,体验并可以使产品更昂贵!毕竟,有某些服务,例如REST API,这些服务收费用于访问...

换句话说,由于重新组件的过量循环,所有进行状态修饰的耳朵都必须在组成的组成之外进行!现在是一个很好的问题:

“我如何执行不受重新组件影响的方式?”

使用副作用API

要执行它不受重新组件的影响,我们需要使用APIs de Side-effect。基本上,此API提供了几种工具,使您可以执行修改状态并不受重新组件影响的状态。

非常常见的可能性之一是LaunchedEffect(),它是一个不发行视觉元素并通过lambda表达式运行coroutine的组合:

var users by remember {
    mutableStateOf(emptyList<User>())
}
LaunchedEffect(null) {
    findAllUsers().collect {
        users = it
    }
}
Column {
    Text(text = "${counter++}")
    for (user in users) {
        Column {
            Text(text = user.id.toString())
            Text(text = user.name)
        }
    }
}

通过此调整,该应用程序没有更多的循环行为!发生这种情况,因为findAllUsers()仅执行一次...现在,让我们了解发生了什么。

了解JetPack Compiss Chaves API

有几个JetPack Compiss Apis接收钥匙作为参数,例如Koud6和Koud4。关键机制是指示组合可执行量的一种方法。

例如,当使用remember而不发送任何密钥时,这意味着它将仅执行一次,因此当使用koud4发送koud10时,这也意味着它将仅执行一次!毕竟,koud10不会更改其价值...

换句话说,如果您打算多次运行这些组合,则会发送一个可变的价值。有摘要?让我们以koud4的示例:

var users by remember {
    mutableStateOf(emptyList<User>())
}
LaunchedEffect(users) {
    findAllUsers().collect {
        users = it
    }
}

随着这种调整,无限环路再次返回,因为每次重新组件发生时,我们都会为users提供一个新值...因此,选择副作用API中的键。P>>

密钥机制可以通过varargs接收多个密钥,并且每次键都具有新值时可以重新执行...

避免在组成的事件中重新组成

避免重新组件问题的另一种方法,它正在使用可复合事件,例如点击事件:

var users by remember {
    mutableStateOf(emptyList<User>())
}
val scope = rememberCoroutineScope()
Column {
    Button(onClick = {
        scope.launch {
            findAllUsers().collect {
                users = it
            }
        }
    }) {
        Text(text = "Find all users")
    }
    // ...
}

App em execução apresentando o botão para buscar todos os usuários e o contador iniciado com zero em coluna. Ao clicar no botão, após alguns segundos, o contador é incrementado e aparece o usuário, ao clicar novamente, apenas o contador é incrementado.

请参阅重新组件仅在执行点击时才发生!这种行为的秘密是这些事件在内部使用副作用API!

避免随着重新分配的流动而循环

另一个重要的细节是,正如我们在初始样本中看到的那样,JetPack Compiss中的流量通常是从转换后的Koud0进行的...

中所看到的。

要使用这种方法并避免无限循环,流程的实现不应改变状态!这意味着流程的暴露仅应是读取或修改数据读取流。

因此,必须在另一个呼叫中进行新排放的更改,该呼叫不会在组成的组成中执行。让我们跟随一个ViewModel的示例:

class UsersViewModel : ViewModel() {

    private val _users = MutableStateFlow(emptyList<User>())
    val users = _users.asStateFlow()

    fun findAllUsers() {
        _users.update {
            listOf(User(1, "alex"))
        }
    }

}

以这种方式,Koud5对返回阅读流的返回,而是发出新值的负责。考虑到这种方法,这种方式往往被称为在构图范围之外,就像副作用的API一样。

要读取此实现中发现的用途,我们将其与属性users(是StateFlow)的对话进行了收集,这些内容将通知每个更改,因为findAllUsers()被调用。看到它是可以合并的:

val viewModel by viewModels<UsersViewModel>()
val users by viewModel.users.collectAsState(
    initial = emptyList()
)
Column {
    Button(onClick = {
        viewModel.findAllUsers()
    }) {
        Text(text = "Find all users")
    }
    Text(text = "${counter++}")
    for (user in users) {
        Column {
            Text(text = user.id.toString())
            Text(text = user.name)
        }
    }
}

请注意,即使流量收集代码为组成,我们也没有循环问题,因为这是一种仅对仅在API和副作用中进行的更新的方式!

,在那里,您如何看待JetPack中重新组成的这些细节?您是否经历了这种类型的十字架上复杂的一些挑战?喜欢分享评论。