JetPack Compose – Gestão do Estado

Tempo de leitura: 3 minutes

Refere-se a gerenciar o estado da interface do usuário ao interagir com widgets como campos de texto, botões, botões de rádio, etc.

O gerenciamento de estado no Android é um conceito complexo e para saber a razão pela qual você deve primeiro entender o projeto arquitetônico do Android e aprender por que é o principal requisito para gerenciar o estado.

“O estado é um objeto que está conectado / inscrito em um ou mais widgets, contém dados e está ansioso para atualizar os widgets a partir desses dados. Se houver alguma alteração nos dados, ele notifica todos os widgets aos quais está conectado. Os valores do estado são alterados em tempo de execução.”

No jetpack compor o conceito de gerenciamento de estado é o mesmo do padrão Observable que afirmava que se houver alguma alteração que ocorra no objeto inscrito, ele aciona todos os seus objetos dependentes automaticamente.

Além do conceito acima, jetpack compose tem alguma mudança funcional, que afirma que as funções subscritas @composable se recompõem com os novos dados quando o valor do estado / objeto é atualizado e não afeta ou atualiza toda a IU.

De acordo com o documento de gestão estadual, o jetpack compõe o estado de suporte de duas formas:

  • MutableStateOf


No passado, usávamos a anotação @Model, mas ela se tornou obsoleta em 0,1.0-dev12. Então, a anotação de state{} foi descontinuada em 0.1.0-dev16.

Vamos discutir isso em detalhes:

remember { mutableStateOf(…) }

É uma versão estendida de State<OriginalClass>

data class Position(
  val x: Int, 
  val y: Int
)

@Composable fun Example() {
    var p by state { Position(0,0) }
    PositionChanger(
      position=p,
      onXChange={ p = p.copy(x=it) },
      onYChange={ p = p.copy(y=it) }
    )
}

Essa abordagem é a mesma que fizemos no estado, a única mudança que vemos é o chamado. Vamos ver o que a equipe composable disse sobre isso:

“Marque o estado composto como obsoleto e promova o uso direto de lembre-se {mutableStateOf(…)} em vez disso para melhor clareza e compreensão da superfície da API de gerenciamento de estado do Compose. Isso reduz a superfície geral da API e o número de conceitos para gerenciamento de estado e corresponde ao padrão `by mutableStateOf()` para delegação de propriedade de classe.”

Neste conceito, o objeto é inicializado no mesmo escopo onde a mutação está implementando. A melhor inicialização possível está dentro da função @compose. Ele também segue o mesmo padrão hierárquico de objeto Kotlin, como passar como uma referência para outra função. Agora, você tem um cenário em que deseja transformar o objeto inicializado fora do escopo, então a próxima abordagem mutableStateOf é útil.

Como usar a abordagem Remember{mutableStateOf (…)}

MutableStateOf

mutableStateOf e delegados de propriedade

data class Position( 
   val x by mutableStateOf(x), 
   val y by mutableStateOf(y) 
) 

// A fonte é igual a anterior 
@Composable fun Example() { 
   var p by state { Position(0,0) } 
   PositionChanger( 
      position=p, 
      onXChange={ p = p.copy(x=it) }, 
      onYChange={ p = p.copy(y=it) } 
   )
}

A API mutableStateOf nos permite criar instâncias de MutableState fora da classe. Nesta abordagem, cada propriedade é observada individualmente, portanto, as recomposições que você vê após este refatoramento podem ser mais estreitas.

Em palavras simples, ele diz que a operação de leitura e gravação em cada propriedade é observada por composição e se houver qualquer alteração de propriedade, o composable aciona todos os índices compostos onde essa propriedade é observada. Também nos dá a propriedade de valor na execution.

Veja todo o conceito de mutableStateOf no exemplo abaixo definido:

//--------------Utils Class start--------------------
sealed class MenuOptions {
    object TaskList : MenuOptions()
    object AddTask : MenuOptions()
    data class ModifyTask(val task: Task) : MenuOptions()
}

object AppMain {
    private var current_screen: MenuOptions = MenuOptions.TaskList
    var route_screen by mutableStateOf(current_screen)
    var taskList by mutableStateOf(mutableListOf<Task>())
}

fun routingActivity(activity: MenuOptions) {
    route_screen = activity
}

//--------------Utils Class end----------------------


//--------------Main Activity------------------------
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            TODOAppGreeting()
        }
    }

    override fun onBackPressed() {
        if (AppMain.route_screen !is MenuOptions.TaskList)
            routingActivity(MenuOptions.TaskList)
        else
            super.onBackPressed()

    }
}

@Composable
fun TODOAppGreeting() {
    MaterialTheme {
        AppContent(AppState())
    }
}

@Composable
fun AppContent(app: AppMain) {
    Crossfade(current = app.route_screen) { activity ->
        Surface(color = MaterialTheme.colors.background) {
            when (activity) {
                is MenuOptions.AddTask -> AddTask()
                is MenuOptions.TaskList -> TaskList()
                is MenuOptions.ModifyTask -> AddTask(activity.task)
            }
        }

    }
}

@Composable
fun AppState(): AppMain {
    //Initialize state
    return remember { AppMain }
}

Obrigado por gastar seu tempo lendo este artigo. Compartilhe se você gostou!