Nota
O acceso a esta páxina require autorización. Pode tentar iniciar sesión ou modificar os directorios.
O acceso a esta páxina require autorización. Pode tentar modificar os directorios.
Cree aplicaciones WinUI con Windows App SDK que empiecen rápidamente al reducir el trabajo de inicio, simplificar el primer fotograma y cargar funciones no críticas una vez que la ventana es interactiva.
Procedimientos recomendados para mejorar el rendimiento del inicio de la aplicación
En parte, los usuarios perciben si la aplicación es rápida o lenta en función del tiempo que se tarda en iniciarse. Para los fines de este tema, el tiempo de inicio de una aplicación comienza cuando el usuario inicia la aplicación y finaliza cuando el usuario puede interactuar con la aplicación de forma significativa. En este artículo se proporcionan sugerencias sobre cómo mejorar el rendimiento de inicio de una aplicación WinUI.
Medición del tiempo de inicio de la aplicación
Asegúrese de iniciar la aplicación varias veces antes de medir realmente su tiempo de inicio. Esto le proporciona una base de referencia para su medición y le ayuda a asegurarse de que está midiendo un tiempo de inicio tan corto como sea razonablemente posible.
Tome medidas que sean representativas de lo que experimentará el usuario final. Compilaciones de prueba se basan en hardware representativo, examinan el inicio en frío y en caliente, y se centran en el tiempo hasta el primer fotograma interactivo en lugar de solo el tiempo hasta que el proceso se inicie.
Aplazar el trabajo siempre que sea posible
Para mejorar el tiempo de inicio de la aplicación, haga solo el trabajo que absolutamente debe realizarse para permitir que el usuario empiece a interactuar con la aplicación. Esto puede ser especialmente beneficioso si puede retrasar la carga de ensamblajes adicionales. Common Language Runtime carga un ensamblado la primera vez que se usa. Si puedes minimizar el número de ensamblados que se cargan, es posible que puedas mejorar el tiempo de inicio de la aplicación y su consumo de memoria.
Realizar tareas de larga duración de forma independiente
La aplicación puede ser interactiva aunque haya partes de la aplicación que no sean totalmente funcionales. Por ejemplo, si la aplicación muestra datos que tardan un tiempo en recuperarse, puede hacer que ese código se ejecute independientemente del código de inicio de la aplicación recuperando los datos de forma asincrónica. Cuando los datos estén disponibles, rellene la interfaz de usuario de la aplicación con los datos.
Muchas de las API que recuperan datos son asincrónicas, por lo que probablemente recuperará datos de forma asincrónica de todos modos. Para obtener más información, consulta Programación asincrónica con async y await. Si haces trabajo que no usa API asincrónicas, puedes usar la Task clase para realizar trabajos de larga duración para que no impidas que el usuario interactúe con la aplicación. Esto mantiene la capacidad de respuesta de la aplicación mientras se cargan los datos.
Si la aplicación tarda mucho tiempo en cargar parte de su interfaz de usuario, considere la posibilidad de mostrar un mensaje en esa área, como "Obtener datos más recientes" para que los usuarios sepan que la aplicación sigue procesando.
Minimizar el tiempo de inicio
Todas las aplicaciones más sencillas requieren una cantidad de tiempo perceivable para cargar recursos, analizar XAML, configurar estructuras de datos y ejecutar lógica durante el inicio. En el caso de las aplicaciones WinUI, ayuda a pensar en el inicio en cuatro fases: inicio del proceso, creación de ventanas, creación de página principal y diseño/representación para el primer fotograma.
El período de inicio es el tiempo entre el momento en que un usuario inicia la aplicación y el momento en que la aplicación se vuelve funcional. Este es un momento crítico porque es la primera impresión de un usuario de la aplicación. Los usuarios esperan comentarios instantáneos y continuos del sistema y de las aplicaciones. El sistema y la aplicación se perciben rotos o mal diseñados cuando las aplicaciones no se inician rápidamente.
Introducción a las fases de inicio
El inicio implica una serie de piezas móviles y todas ellas deben coordinarse para obtener la mejor experiencia del usuario. Los pasos siguientes se producen entre el usuario que inicia la aplicación y el contenido de la aplicación que se muestra.
- El proceso se inicia y el código de inicio generado a partir de plantillas llama a
Main. - Se crea el
Applicationobjeto .- El constructor de la aplicación llama a
InitializeComponent, lo que provoca queApp.xamlse analice y se creen objetos.
- El constructor de la aplicación llama a
-
Application.OnLaunched es invocado.
- El código de la aplicación crea la ventana principal, asigna el contenido inicial y llama a
Activate. - El constructor principal llama a
InitializeComponent, provocando el análisis del XAML de la página y la creación de objetos.
- El código de la aplicación crea la ventana principal, asigna el contenido inicial y llama a
- El marco XAML ejecuta el proceso de diseño, incluida la medición y disposición.
-
ApplyTemplateprovoca que se cree el contenido de la plantilla de control para cada control, lo que suele ocupar la mayor parte del tiempo de maquetación durante el inicio.
-
- Render crea objetos visuales para el contenido de la ventana.
- El primer fotograma se presenta y el trabajo posterior al inicio continúa de forma asincrónica.
Haz menos en tu camino de emprendimiento
Mantenga la ruta del código de inicio libre de elementos innecesarios para su primer fotograma.
- Si tiene dll de usuario que contienen controles que no son necesarios durante el primer fotograma, considere la posibilidad de retrasar su carga.
- Si tiene una parte de la interfaz de usuario que depende de los datos de la nube, divida esa interfaz de usuario. En primer lugar, abra la interfaz de usuario que no depende de los datos en la nube y, a continuación, abra de forma asincrónica la interfaz de usuario dependiente de la nube. También debe considerar la posibilidad de almacenar en caché los datos localmente para que la aplicación pueda funcionar sin conexión o no verse afectada por la conectividad de red lenta.
- Muestra la interfaz de usuario de avance si tu interfaz está a la espera de datos.
- Tenga cuidado con los diseños de aplicaciones que implican un gran análisis de archivos de configuración o interfaz de usuario que se genera dinámicamente mediante código.
Reducción del número de elementos
El rendimiento de inicio en una aplicación XAML se correlaciona directamente con el número de elementos que se crean durante el inicio. Cuantos menos elementos cree, menos tiempo tardará la aplicación en iniciarse. Como un punto de referencia aproximado, considere que cada elemento tarda 1 ms en crearse.
- Las plantillas usadas en los controles de elementos pueden tener el mayor impacto, ya que se repiten varias veces. Consulte Optimización de la interfaz de usuario de ListView y GridView.
- Los controles de usuario y las plantillas de control se expanden, por lo que también se deben tener en cuenta.
- Si creas cualquier XAML que no aparezca en la pantalla, debes justificar si esas partes de XAML se deben crear durante el inicio.
En la ventana Árbol visual dinámico de Visual Studio se muestran los recuentos de elementos secundarios para cada nodo del árbol.
Utilice el aplazamiento. Al colapsar un elemento o establecer su opacidad en 0, no se evita que se cree el elemento. Con x:Load o x:DeferLoadStrategy, puede retrasar la carga de una parte de la interfaz de usuario y cargarla cuando sea necesario. Esta es una buena manera de retrasar el procesamiento de la interfaz de usuario que no se muestra durante el inicio para que pueda cargarse cuando sea necesario o como parte de un conjunto de lógica diferida. Para desencadenar la carga, solo necesita llamar FindName al elemento . Para obtener un ejemplo y más información, vea el atributo x:Load y el atributo x:DeferLoadStrategy.
Virtualización. Si tiene contenido de lista o repetidor en la interfaz de usuario, se recomienda encarecidamente usar la virtualización de la interfaz de usuario. Si la interfaz de usuario de la lista no está virtualizada, estarás pagando el costo de crear todos los elementos de antemano, lo que puede ralentizar el inicio del sistema. Consulte Optimización de la interfaz de usuario de ListView y GridView.
El rendimiento de una aplicación no solo es una cuestión de rendimiento bruto; también tiene que ver con la percepción. Cambiar el orden de las operaciones para que los aspectos visuales se produzcan en primer lugar hace que el usuario sienta que la aplicación es más rápida. Los usuarios consideran la aplicación cargada cuando el contenido está en la pantalla. Normalmente, las aplicaciones necesitan hacer varias cosas durante el inicio y no todo ese trabajo es necesario para abrir la interfaz de usuario, por lo que esas partes deben retrasarse o priorizarse por debajo de la interfaz de usuario.
En este artículo se habla sobre el primer fotograma, que procede de la terminología de animación y vídeo, y es una medida de cuánto tiempo tarda hasta que el usuario final ve el contenido.
Mejora de la percepción del inicio
Vamos a usar el ejemplo de un juego en línea sencillo para identificar cada fase de inicio y diferentes técnicas para proporcionar a los usuarios comentarios a lo largo del proceso.
En la primera fase, el proceso se inicia y la aplicación crea su ventana. Durante este tiempo, el usuario aún no ha visto el contenido propio de la aplicación. Su objetivo es obtener rápidamente una ventana ligera en la pantalla.
La segunda fase abarca la creación e inicialización de las estructuras críticas para el juego. Si la aplicación puede crear rápidamente su interfaz de usuario inicial con los datos disponibles en el inicio, esta fase es trivial y puede mostrar la interfaz de usuario inmediatamente. De lo contrario, muestra una página de carga ligera mientras se inicializa la aplicación.
El aspecto de la página de carga es para usted; puede ser tan simple como mostrar una barra de progreso o un anillo de progreso. El punto clave es que la aplicación indica que está realizando tareas antes de que se vuelva completamente responsiva. En el caso del juego, la pantalla inicial requiere que algunas imágenes y sonidos se carguen desde el disco en la memoria. Estas tareas tardan tiempo, por lo que la aplicación mantiene informado al usuario mostrando una página de carga con una animación sencilla relacionada con el tema del juego.
La tercera fase comienza después de que el juego tenga un conjunto mínimo de información para crear una interfaz de usuario interactiva, que reemplaza la página de carga. En este momento, la única información disponible para el juego en línea puede ser el contenido que la aplicación cargó desde el disco. El juego puede enviar contenido suficiente para crear una interfaz de usuario interactiva, pero porque es un juego en línea, no será totalmente funcional hasta que se conecte a Internet y descargue cierta información adicional. Hasta que tenga toda la información que necesita, el usuario puede interactuar con la interfaz de usuario (IU), pero las funcionalidades que requieren datos adicionales de la web deben indicar que el contenido aún se está cargando. Una aplicación puede tardar algún tiempo en funcionar completamente, por lo que es importante que la funcionalidad esté disponible lo antes posible.
Ahora que hemos identificado las tres fases de inicio en el juego en línea, vamos a vincularlas al código real.
Fase 1 y Fase 2
Use el constructor de la aplicación solo para inicializar estructuras de datos críticas para la aplicación. Siga OnLaunched centrándose en la creación de la primera ventana rápidamente, la asignación de contenido ligero y la activación de la ventana para que la aplicación pueda mostrar los comentarios inmediatamente.
public partial class App : Application
{
public static Window MainWindow { get; private set; } = null!;
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
base.OnLaunched(args);
MainWindow = new MainWindow();
MainWindow.Content = new LoadingPage();
MainWindow.Activate();
_ = InitializeAsync();
}
private async Task InitializeAsync()
{
// Asynchronously restore state and load the minimum data needed
// to create the first interactive UI.
await LoadInitialDataAsync();
MainWindow.Content = new GameHomePage();
}
private static Task LoadInitialDataAsync()
{
// Download data to populate the initial UI.
return Task.CompletedTask;
}
}
Una de las tareas clave de OnLaunched es crear una interfaz de usuario, asignarla a Window.Content y, a continuación, llamar a Window.Activate. Si necesita más de un flujo de activación, mantenga el mismo principio: mostrar contenido ligero rápidamente y mover el trabajo costoso fuera de la ruta de inicio crítica.
Las aplicaciones que muestran una página de carga durante el inicio pueden comenzar a funcionar para crear la interfaz de usuario principal en segundo plano. Una vez creado ese elemento, se produce su evento FrameworkElement.Loaded . En el controlador de eventos, puede reemplazar el contenido de la ventana, que actualmente es la pantalla de carga, por la página principal recién creada.
Es fundamental que una aplicación con un período de inicialización extendido muestre una página de carga. Además de proporcionar comentarios sobre el proceso de inicio, la ventana debe activarse rápidamente para que los usuarios vean que la aplicación está progresando.
partial class GameHomePage : Page
{
public GameHomePage()
{
InitializeComponent();
// Add a handler to be called when the home page has been loaded.
Loaded += GameHomePageLoaded;
// Load the minimal amount of image and sound data from disk necessary
// to create the home page.
}
private void GameHomePageLoaded(object sender, RoutedEventArgs e)
{
// Set the content of the main window to the home page now that it's
// ready to be displayed.
App.MainWindow.Content = this;
}
}
Fase 3
Solo porque la aplicación muestra la interfaz de usuario no significa que esté completamente lista para su uso. En el caso de nuestro juego, la interfaz de usuario se muestra con marcadores de posición para las características que requieren datos de Internet. En este momento, el juego descarga los datos adicionales necesarios para que la aplicación sea totalmente funcional y permite progresivamente las características a medida que se adquieren los datos.
A veces, gran parte del contenido necesario para el inicio se puede empaquetar con la aplicación. Tal es el caso de un juego simple. Esto hace que el proceso de inicio sea bastante sencillo. Pero muchos programas, como lectores de noticias y visores de fotos, deben extraer información de la web para ser funcional. Estos datos pueden ser grandes y pueden tardar bastante tiempo en descargarse. La forma en que la aplicación obtiene estos datos durante el inicio puede tener un gran impacto en el rendimiento percibido.
Puede mostrar una página de carga durante demasiado tiempo si una aplicación intentó descargar un conjunto de datos completo que necesita para la funcionalidad en la primera o segunda fase del inicio. Eso hace que una aplicación parezca colgada. Se recomienda que una aplicación descargue la cantidad mínima de datos necesarios para mostrar una interfaz de usuario interactiva con elementos de marcador de posición en la fase 2 y, a continuación, cargar progresivamente los datos, que reemplaza los elementos de marcador de posición, en la fase 3. Para obtener más información sobre cómo tratar los datos, consulta Optimizar ListView y GridView.
La forma en que una aplicación reacciona a cada fase de inicio depende completamente de ti, pero proporcionar al usuario tanta retroalimentación como sea posible mediante una interfaz de usuario ligera inicial, junto con pantallas de carga y carga progresiva de datos, hace que la aplicación parezca más rápida.
Minimizar los ensamblados administrados en la ruta de inicio
El código reutilizable suele tener la forma de módulos (DLL) incluidos en un proyecto. La carga de estos módulos requiere acceder al disco, y el costo puede acumularse. Esto tiene el mayor impacto en el inicio en frío, pero también puede afectar al inicio cálido. En las aplicaciones .NET, el CLR intenta retrasar ese costo tanto como sea posible cargando los ensamblados bajo demanda. Es decir, CLR no carga un módulo hasta que un método ejecutado hace referencia a él. Por lo tanto, haga referencia solo a los ensamblados necesarios para el inicio de la aplicación en el código de inicio para que CLR no cargue módulos innecesarios. Si tiene rutas de acceso de código no usadas en la ruta de acceso de inicio que tienen referencias innecesarias, mueva estas rutas de acceso de código a otros métodos para evitar las cargas innecesarias.
Otra manera de reducir las cargas de módulos es combinar módulos de aplicación. La carga de un ensamblado grande suele tardar menos tiempo que cargar dos pequeños. Esto no siempre es posible y solo debe combinar módulos si no hace una diferencia material para la productividad del desarrollador o la reutilización de código. Puede usar herramientas como PerfView o Windows Performance Analyzer (WPA) para averiguar qué módulos se cargan al iniciarse.
Realización de solicitudes web inteligentes
Puedes mejorar drásticamente el tiempo de carga de una aplicación empaquetando su contenido localmente, incluidos XAML, imágenes y cualquier otro archivo importante para la aplicación. Las operaciones de disco son más rápidas que las operaciones de red. Si una aplicación necesita un archivo determinado en la inicialización, puede reducir el tiempo de inicio general cargando desde el disco en lugar de recuperarlo desde un servidor remoto.
Páginas de diario y caché de forma eficaz
El Frame control proporciona características de navegación. Ofrece navegación a una página (método Navigate), registro en diario de navegación (propiedades BackStack y ForwardStack, métodos GoForward y GoBack), almacenamiento en caché de páginas (Page.NavigationCacheMode), y compatibilidad con serialización (método GetNavigationState).
El rendimiento que se debe tener en cuenta con Frame se basa principalmente en el registro en diario y el almacenamiento en caché de páginas.
Diario de fotogramas. Al navegar a una página con Frame.Navigate, se agrega un PageStackEntry para la página actual a la Frame.BackStack colección.
PageStackEntry es relativamente pequeño, pero no hay ningún límite integrado para el tamaño de la BackStack colección. Potencialmente, un usuario podría navegar por un bucle y aumentar esta colección indefinidamente.
PageStackEntry también incluye el parámetro que se pasó al método Frame.Navigate. Se recomienda que ese parámetro sea un tipo serializable primitivo, como o intstring, para permitir que el Frame.GetNavigationState método funcione. Pero ese parámetro podría referirse a un objeto que represente cantidades más significativas del conjunto de trabajo u otros recursos, lo que hace que cada entrada en BackStack se vuelva mucho más costosa. Por ejemplo, podría usar un StorageFile elemento como parámetro y, por tanto BackStack , podría mantener abierto un número indefinido de archivos.
Por lo tanto, se recomienda mantener pequeños los parámetros de navegación y limitar el tamaño de BackStack.
BackStack es una colección estándar en C#, por lo que se puede recortar simplemente quitando entradas.
Almacenamiento en caché de páginas. De forma predeterminada, cuando se navega a una página con el Frame.Navigate método , se crea una instancia nueva de la página. Del mismo modo, si vuelve a la página anterior con Frame.GoBack, se asigna una nueva instancia de la página anterior.
Frame también ofrece una caché de páginas opcional que puede evitar estas instanciaciones. Para obtener una página puesta en la memoria caché, use la Page.NavigationCacheMode propiedad . Establecer ese modo en Required obliga a que la página se almacene en caché, mientras que establecerlo en Enabled permite que se almacene en caché. De forma predeterminada, el tamaño de caché es de 10 páginas, pero esto se puede invalidar con la Frame.CacheSize propiedad . Todas las Required páginas se almacenan en caché y, si hay menos de CacheSize páginas necesarias, también se pueden almacenar en caché las Enabled páginas.
El almacenamiento en caché de páginas puede ayudar al rendimiento evitando las instancias y, por tanto, mejorando el rendimiento de la navegación. El almacenamiento en caché de páginas puede afectar al rendimiento mediante el almacenamiento en caché excesivo y, por tanto, afectar al conjunto de trabajo.
Por lo tanto, se recomienda usar el almacenamiento en caché de páginas según corresponda para la aplicación. Por ejemplo, supongamos que tiene una aplicación que muestra una lista de elementos de un Framey, al seleccionar un elemento, navega el marco a una página de detalles de ese elemento. Es probable que la página de lista se establezca en caché. Si la página de detalles es la misma para todos los elementos, probablemente también debe almacenarse en caché. Pero si la página de detalles es más heterogénea, es posible que sea mejor dejar el almacenamiento en caché.
Windows developer