Compartilhar via


Criar aplicativos de tela grandes e complexos

A maioria dos artigos nesta seção da documentação aborda o desempenho de runtime dos aplicativos conforme experimentado pelas pessoas que os usam. Este artigo aborda o desempenho do aplicativo conforme experimentado pelas pessoas que os fazem.

À medida que os aplicativos se tornam maiores e mais complexos, o Power Apps Studio precisa carregar e gerenciar um número maior de controles, fórmulas e fontes de dados, tudo isso com interdependências que crescem exponencialmente. O Power Apps Studio pode levar mais tempo para ser carregado, e recursos como IntelliSense e codificação de cores podem ser atrasados. Use as recomendações a seguir para trabalhar melhor com aplicativos grandes e complexos no Power Apps Studio. Eles também podem ajudar a melhorar o desempenho do runtime de seus aplicativos.

Os exemplos neste artigo usam a solução de exemplo de Resposta de Emergência Hospitalar.

Usar App.Formulas em vez de App.OnStart

Dica

Você pode usar a função With e as propriedades de saída personalizadas do componente de função e tela como alternativa a fórmulas nomeadas.

A melhor maneira de reduzir o tempo de carregamento para o Power Apps Studio e seu aplicativo é substituir a inicialização de variável e coleção no App.OnStart por fórmulas nomeadas em App.Formulas.

Vamos examinar o exemplo a seguir, que usa App.OnStart.

// Get the color of text on a dark background.
Set(varColorOnDark,RGBA(0, 0, 0, 1));

// Get the color of the menu icons.
Set(varColorMenuIcon,"#0070a9");

// Get the styles for a form.
Set(varFormStyle,
    {
        DataCard: { Height: 50 },
        Title: { Height: 50, Size: 21, Color: varColorOnDark },
        Control: { Height: 50, Size: 18 },
        Label: { Size: 18, Color: varColorOnDark }
    }
);

ClearCollect(
    FacilitiesList,
    ForAll(
        Facilities,
        { Name: 'Facility Name', Id: Facility }
    )
);
If(
    Not IsBlank(Param("FacilityID")),
    Set(ParamFacility,
        LookUp(
            FacilitiesList,
            Id = GUID(Param("FacilityID"))
        ).Name
    );
);

Como elas são uma sequência de instruções, seu aplicativo deve avaliar essas chamadas Definir e Coletar em ordem antes que ela possa exibir a primeira tela, o que faz com que o aplicativo seja carregado mais lentamente. E como todo o App.OnStart deve ser considerado como um todo, a ordem preservada e os erros agregados antes de retornar o resultado final, a fórmula é complexa para o Power Apps Studio analisar.

Há uma maneira melhor. Em vez disso, use App.Formulas e defina essas variáveis e coleções como fórmulas nomeadas, como no exemplo a seguir.

// Get the color of text on a dark background.
varColorOnDark = RGBA(0, 0, 0, 1);

// Get the color of the menu icons.
varColorMenuIcon = "#0070a9";

// Get the styles for a form.
varFormStyle = 
    {
        DataCard: { Height: 50 },
        Title: { Height: 50, Size: 21, Color: varColorOnDark },
        Control: { Height: 50, Size: 18 },
        Label: { Size: 18, Color: varColorOnDark }
    };

FacilitiesList =
    ForAll(
        Facilities,
        { Name: 'Facility Name', Id: Facility }
    );

ParamFacility = 
    If( Not IsBlank(Param("FacilityID")),
        LookUp(
            FacilitiesList,
            Id = GUID(Param("FacilityID"))
        ).Name,
        Blank()
    );

Essa mudança pode parecer pequena, mas pode ter um enorme impacto. Como cada fórmula nomeada é independente das outras, o Power Apps Studio pode analisá-las de forma independente, dividindo efetivamente um App.OnStart grande em partes menores. Vimos o tempo de carregamento do Power Apps Studio cair em até 80% apenas com essa alteração.

Seu aplicativo também é carregado mais rápido porque não precisa avaliar essas fórmulas até que precise do resultado. A primeira tela do aplicativo é exibida imediatamente.

Fórmulas nomeadas não podem ser usadas em todas as situações porque você não pode modificá-las ou usá-las com Set. Algumas situações exigem o uso de uma variável de estado que pode ser modificada. O conjunto é perfeito para essas situações e você deve continuar a usá-lo. Mas, na maioria das vezes, você está usando variáveis globais no OnStart para configurar valores estáticos que não são alterados. Nesses casos, uma fórmula nomeada é a melhor opção.

Como as fórmulas nomeadas são imutáveis, o prefixo var (abreviação de "variável") como uma convenção de nomenclatura não é mais apropriado. Não alteramos os nomes neste exemplo porque ele exigiria alterações no restante do aplicativo para corresponder.

É tentador colocar uma fórmula nomeada em App.OnStart, mas não coloque. Eles não pertencem lá. Como uma propriedade "On" de comportamento, App.OnStart avalia cada uma de suas instruções em ordem, criando variáveis globais e interagindo com bancos de dados apenas uma vez, quando o aplicativo é carregado. Fórmulas nomeadas são fórmulas que definem como calcular algo sempre que necessário e são sempre verdadeiras. É essa natureza da fórmula que permite que eles sejam independentes e permite que o aplicativo conclua o carregamento antes de ser avaliado.

Dividir fórmulas longas

App.OnStart é um dos piores infratores para fórmulas longas e definitivamente por onde você deve começar, mas não é o único caso.

Nossos estudos mostraram que quase todos os aplicativos com um longo tempo de carga para o Power Apps Studio têm pelo menos uma fórmula de mais de 256.000 caracteres. Alguns aplicativos com os tempos de carga mais longos têm fórmulas de mais de 1 milhão de caracteres. Fórmulas que exercem uma pressão significativa no Power Apps Studio por muito tempo.

Para piorar as coisas, copiar e colar um controle com uma fórmula longa duplica a fórmula nas propriedades do controle sem que se perceba. O Power Apps é modelado após o Excel, onde várias cópias de uma fórmula são comuns. No entanto, as fórmulas do Excel são limitadas a uma expressão e são limitadas a 8.000 caracteres. As fórmulas do Power Apps podem crescer muito mais com a introdução da lógica imperativa e do operador de encadeamento (; ou ;;, dependendo da localidade).

A solução geral é dividir fórmulas longas em partes menores e reutilizar as partes, como fizemos na seção anterior, quando alteramos as instruções Set/Collect no App.OnStart para fórmulas nomeadas em App.Formulas. Em outras linguagens de programação, as partes reutilizáveis geralmente são conhecidas como sub-rotinas ou funções definidas pelo usuário. Você pode pensar em fórmulas nomeadas como uma forma simples de função definida pelo usuário sem parâmetros ou efeitos colaterais.

Usar fórmulas nomeadas em todos os lugares

No exemplo anterior, usamos fórmulas nomeadas como uma substituição para App.OnStart. No entanto, você pode usá-los para substituir um cálculo em qualquer lugar em um aplicativo.

Por exemplo, uma das telas na solução de exemplo Hospital Emergency Response inclui essa lógica em Screen.OnVisible:

ClearCollect(
    MySplashSelectionsCollection,
    {
        MySystemCol: First(
            Filter(
                Regions,
                Region = MyParamRegion
            )
        ).System.'System Name',
        MyRegionCol: First(
            Filter(
                Regions,
                Region = MyParamRegion
            )
        ).'Region Name',
        MyFacilityCol: ParamFacility,
          MyFacilityColID:  LookUp(
            FacilitiesList,
            Id = GUID(Param("FacilityID"))
        ).Id
    }
); 

Essa fórmula pode ser dividida em um conjunto de fórmulas nomeadas. Também facilita a leitura da fórmula.

MyRegion = LookUp(
                    Regions,
                    Region = MyParamRegion
           );

MyFacility = LookUp(
                    FacilitiesList,
                    Id = GUID(Param("FacilityID")
            );

MySplashSelectionsCollection = 
    {
        MySystemCol: MyRegion.System.'System Name',
        MyRegionCol: MyRegion.'Region Name',
        MyFacilityCol: ParamFacility,
        MyFacilityColID:  MyFacility.Id
    };

Extraímos ParamFacility como uma fórmula nomeada anteriormente quando movemos a maioria das chamadas Set de App.OnStart para fórmulas nomeadas em App.Formulas.

As fórmulas nomeadas são avaliadas somente quando seus valores são necessários. Se a intenção original do uso de Screen.OnVisible era adiar o trabalho até a tela ser mostrada, então o trabalho ainda será adiado como fórmulas nomeadas globais em App.Formulas.

Usar a função With

Você também pode usar a função With em uma fórmula para dividir a lógica. Crie um registro no primeiro parâmetro com os valores que você deseja usar como campos e use esses campos no segundo parâmetro para calcular o valor retornado de With. Por exemplo, o exemplo anterior pode ser escrito como apenas uma fórmula nomeada:

MySplashSelectionsCollection = 
    With( { MyRegion: LookUp(
                            Regions,
                            Region = MyParamRegion
                      ),
            MyFacility: LookUp(
                            FacilitiesList,
                            Id = GUID(Param("FacilityID")
                      ) 
           },
           {
                MySystemCol: MyRegion.System.'System Name',
                MyRegionCol: MyRegion.'Region Name',
                MyFacilityCol: ParamFacility,
                MyFacilityColID:  MyFacility.Id
           }
    )

Uma desvantagem de utilizar With dessa forma é que MyFacility não se pode usar MyRegion porque são definidos na mesma função With, um problema que não ocorre com fórmulas nomeadas. Uma solução é aninhar funções With e usar a palavra-chave As para nomear o registro de cada uma para facilitar o acesso a todas as variáveis With.

Usar componentes de tela

Os componentes de tela geralmente são usados para criar um controle de interface do usuário que pode ser colocado na tela, assim como um controle. Você também pode usá-los sem colocá-los na interface do usuário para executar cálculos com propriedades de saída personalizadas como uma alternativa às fórmulas nomeadas. Os componentes da tela são fáceis de compartilhar entre aplicativos com bibliotecas de componentes e, diferentemente das fórmulas nomeadas, são totalmente compatíveis. No entanto, eles são mais difíceis de configurar e usar do que fórmulas nomeadas.

Para dividir a lógica:

  1. No Power Apps Studio, alterne para a guia Componentes na exibição Árvore.
  2. Crie um novo componente.
  3. No painel Propriedades, ative Escopo do aplicativo Access.
  4. Adicione uma propriedade personalizada.
  5. Defina o tipo de propriedade como Saída e o tipo de dados conforme apropriado.
  6. Selecione Criar.
  7. No seletor de propriedades ao lado da barra de fórmulas na parte superior da tela, selecione a nova propriedade.
  8. Escreva a fórmula da lógica para dividir e reutilizar.

Para usar a lógica:

  1. Alterne para a guia Telas do Exibição de árvore.
  2. No painel Inserir, expanda Personalizado e insira seu componente.
  3. Para calcular um valor com a propriedade, use ComponentName.PropertyName.

Usar Select com um controle oculto para lógica imperativa

A lógica imperativa é usada para modificar o estado com Set e Collect, notificar o usuário com Notify, navegar até outra tela ou aplicativo com Navegar e Iniciar e gravar valores em um banco de dados com Patch, SubmitForm ou RemoveIf.

Fórmulas nomeadas e propriedades de saída personalizadas do componente de tela não suportam lógica imperativa. Uma maneira comum de dividir a lógica imperativa é usar a propriedade OnSelect de um controle oculto.

  1. Adicione um controle Button a uma tela.
  2. Defina a propriedade OnSelect como a lógica imperativa que você deseja executar.
  3. Defina a propriedade Visible como false, pois não há necessidade de o usuário ver ou interagir com ela.
  4. Chame Select( Button ) quando quiser executar a lógica imperativa.

Por exemplo, uma das telas em nosso exemplo tem a seguinte propriedade OnSelect em um controle Button . (Este exemplo simples é somente para fins ilustrativos. Normalmente, você só usaria essa técnica para fórmulas mais longas.)

btnAction_17.OnSelect = 
    Trace("Feedback Screen: Submit Button",TraceSeverity.Information);
    If(
        // Proceed if all forms are validated.
        And(
            FormFeedback.Valid
        ),
    
        // Set the updates to static variables.
        Set(updatesFeedback,Patch(Defaults('App Feedbacks'), FormFeedback.Updates));
        // Submit the first form. Subsequent actions can be found in the OnSuccess.
        SubmitForm(FormFeedback);
        ,
    
        Notify("Please complete all fields before proceeding",
               NotificationType.Warning,2000)
    );

Para dividir essa lógica em partes, podemos colocar porções em controles de Botão separados e selecioná-los a partir do original:

btnTrace.OnSelect = 
    Trace("Feedback Screen: Submit Button",TraceSeverity.Information);

btnSubmit.OnSelect = 
    If(
        // Proceed if all forms are validated.
        And(
            FormFeedback.Valid
        ),
    
        // Set the updates to static variables.
        Set(updatesFeedback,Patch(Defaults('App Feedbacks'), FormFeedback.Updates));
        // Submit the first form. Subsequent actions can be found in OnSuccess.
        SubmitForm(FormFeedback);
        ,
    
        Notify("Please complete all fields before proceeding",
               NotificationType.Warning,2000)
    );

btnAction_17.OnSelect = 
    Select( btnTrace );
    Select( btnSubmit );

Essa técnica só funciona na mesma tela. Outras técnicas que são um pouco mais complicadas funcionam entre diferentes telas, como usar o controle Alternar, definir OnCheck com a lógica que você deseja executar e definir Padrão para uma variável global e então alternar a variável global com Set( global, true ); Set( global, false ) no ponto em que você deseja executar a lógica.

Neste exemplo, algumas divisões lógicas já haviam sido feitas. O comentário menciona que "Ações subsequentes podem ser encontradas no OnSuccess". Esse evento executa a lógica imperativa depois que o registro foi enviado com êxito, uma solução específica para a função SubmitForm .

Particionar o aplicativo

Alguns aplicativos crescem para milhares de controles e centenas de fontes de dados, o que atrasa o Power Apps Studio. Assim como em fórmulas longas, aplicativos grandes podem ser divididos em seções menores que funcionam juntas para criar uma experiência de usuário.

Separar aplicativos de tela

Uma abordagem é implementar seções em apps de canvas separados e usar a função Launch para navegar entre os apps separados e passar o contexto necessário.

Essa abordagem foi usada na solução de exemplo de Resposta a Emergências Hospitalares. Aplicativos separados gerenciam cada uma das principais áreas do aplicativo geral. Os aplicativos compartilham um componente de comutador comum por meio de uma biblioteca de componentes que cada aplicativo mostra em sua tela de inicialização:

Captura de tela do aplicativo de tela da solução de exemplo Hospital Emergency Response em execução em um telefone, mostrando o componente do menu de controle

Quando o usuário seleciona uma área, o componente usa metadados sobre os aplicativos disponíveis e qual aplicativo está hospedando o componente. Se a tela desejada estiver neste aplicativo (ou seja, ThisItem.Screen não estiver em branco), uma chamada navegar será feita. Mas se a tela desejada estiver em um aplicativo diferente (ou seja, ThisItem.PowerAppID não estiver em branco), uma função de Inicialização será usada com a ID do aplicativo do destino e o contexto facilityID:

If(
    IsBlank(ThisItem.Screen),
    If(IsBlank(ThisItem.PowerAppID), 
        Launch(ThisItem.URL),           
        Launch("/providers/Microsoft.PowerApps/apps/" & ThisItem.PowerAppID, 
               "FacilityID", Home_Facility_DD.Selected.Id)
    ),
    Navigate(
        ThisItem.Screen,
        Fade
    )
);

O estado no aplicativo original é perdido quando outro aplicativo é iniciado. Salve qualquer estado antes de chamar a função Launch. Escreva-o em um banco de dados, chame SaveData ou passe o estado para o aplicativo de destino com parâmetros lidos com a função Param .

Aplicativo controlado por modelos com páginas personalizadas

As seções também podem ser implementadas como páginas personalizadas. As páginas personalizadas atuam como um mini aplicativo Canvas, com um contêiner de aplicativo baseado em modelo para navegação.