Información general sobre la compatibilidad con Async
C# 5 introdujo dos palabras clave para simplificar la programación asincrónica: async y await. Estas palabras clave permiten escribir código simple que usa la biblioteca de tareas paralelas para ejecutar operaciones de larga duración (como el acceso a la red) en otro subproceso y acceder fácilmente a los resultados al finalizar. Las versiones más recientes de Xamarin.iOS y Xamarin.Android admiten async y await. En este documento se proporcionan explicaciones y un ejemplo del uso de la nueva sintaxis con Xamarin.
La compatibilidad con Async de Xamarin se basa en mono 3.0 y actualiza el perfil de API de siendo una versión compatible con dispositivos móviles de Silverlight para que sea una versión compatible con dispositivos móviles de .NET 4.5.
Información general
En este documento se presentan las nuevas palabras clave async y await y, a continuación, se le guía por algunos ejemplos sencillos de implementación de métodos asincrónicos en Xamarin.iOS y Xamarin.Android.
Para obtener una explicación más completa de las nuevas características asincrónicas de C# 5 (incluidas una gran cantidad de ejemplos y diferentes escenarios de uso), consulte el artículo Programación asincrónica.
La aplicación de ejemplo realiza una solicitud web asincrónica simple (sin bloquear el subproceso principal) y, a continuación, actualiza la interfaz de usuario con el código HTML y el número de caracteres descargados.
La compatibilidad asincrónica de Xamarin se basa en mono 3.0 y actualiza el perfil de API desde que es una versión compatible para dispositivos móviles de Silverlight para que sea una versión compatible con dispositivos móviles de .NET 4.5.
Requisitos
Las características de C# 5 requieren Mono 3.0 que se incluye en Xamarin.iOS 6.4 y Xamarin.Android 4.8. Se le pedirá que actualice Mono, Xamarin.iOS, Xamarin.Android y Xamarin.Mac para aprovecharlo.
Uso de async & await
async y son nuevas características del lenguaje C# que funcionan junto con la biblioteca de tareas paralelas para facilitar la escritura de código en subprocesos para realizar tareas de ejecución larga sin bloquear el subproceso principal de la await aplicación.
async
Declaración
La palabra clave se coloca en una declaración de método (o en un método lambda o anónimo) para indicar que contiene código que se puede ejecutar de forma asincrónica, es decir, no bloquear el subproceso del autor de async la llamada.
Un método marcado con async debe contener al menos una expresión o instrucción await. Si no hay ninguna instrucción en el método , se ejecutará sincrónicamente await (igual que si no hubiera ningún async modificador). Esto también producirá una advertencia del compilador (pero no un error).
Tipos de valor devuelto
Un método asincrónico debe devolver Task , Task<TResult> o void .
Especifique el Task tipo de valor devuelto si el método no devuelve ningún otro valor.
Especifique si el método necesita devolver un valor, donde es el tipo que se devuelve Task<TResult>TResult (por int ejemplo, ).
El void tipo de valor devuelto se usa principalmente para los controladores de eventos que lo requieren. El código que llama a métodos asincrónicos que devuelven void no puede await en el resultado.
Parámetros
Los métodos asincrónicos no pueden ref declarar out parámetros o .
await
El operador await se puede aplicar a una tarea dentro de un método marcado como asincrónico. Hace que el método detenga la ejecución en ese momento y espere hasta que se complete la tarea.
El uso de await no bloquea el subproceso del autor de la llamada; en su lugar, el control se devuelve al autor de la llamada. Esto significa que el subproceso que realiza la llamada no está bloqueado, por lo que, por ejemplo, el subproceso de la interfaz de usuario no se bloquearía al esperar una tarea.
Cuando se completa la tarea, el método reanuda la ejecución en el mismo punto del código. Esto incluye volver al ámbito try de un bloque try-catch-finally (si hay alguno). await no se puede usar en un bloque catch o finally.
Obtenga más información sobre await en Microsoft Docs.
Control de excepciones
Las excepciones que se producen dentro de un método asincrónico se almacenan en la tarea y se inician cuando se await ed. Estas excepciones se pueden detectar y controlar dentro de un bloque try-catch.
Cancelación
Los métodos asincrónicos que llevan mucho tiempo en completarse deben admitir la cancelación. Normalmente, la cancelación se invoca de la siguiente manera:
- Se
CancellationTokenSourcecrea un objeto . - La
CancellationTokenSource.Tokeninstancia se pasa a un método asincrónico cancelable. - La cancelación se solicita mediante una llamada al
CancellationTokenSource.Cancelmétodo .
A continuación, la tarea se cancela y confirma la cancelación.
Para más información sobre la cancelación, vea Fine-Tuning Your Async Application (C#) (Ajustar la aplicación asincrónica [C#]).
Ejemplo
Descargue la solución xamarin de ejemplo (para iOS y Android) para ver un ejemplo práctico de y en aplicaciones await móviles. El código de ejemplo se describe con más detalle en esta sección.
Escritura de un método asincrónico
El método siguiente muestra cómo codificar un async método con una tarea await ed:
public async Task<int> DownloadHomepage()
{
var httpClient = new HttpClient(); // Xamarin supports HttpClient!
Task<string> contentsTask = httpClient.GetStringAsync("https://visualstudio.microsoft.com/xamarin"); // async method!
// await! control returns to the caller and the task continues to run on another thread
string contents = await contentsTask;
ResultEditText.Text += "DownloadHomepage method continues after async call. . . . .\n";
// After contentTask completes, you can calculate the length of the string.
int exampleInt = contents.Length;
ResultEditText.Text += "Downloaded the html and found out the length.\n\n\n";
ResultEditText.Text += contents; // just dump the entire HTML
return exampleInt; // Task<TResult> returns an object of type TResult, in this case int
}
Tenga en cuenta estos puntos:
- La declaración del método incluye la palabra
asyncclave . - El tipo de valor devuelto
Task<int>es por lo que el código de llamada puede tener acceso al valor que se calcula en esteintmétodo. - La instrucción return es un objeto entero; el hecho de
return exampleInt;que el método devuelva forma parte de las mejoras delTask<int>lenguaje.
Llamada a un método asincrónico 1
Este controlador de eventos de clic de botón se puede encontrar en la aplicación de ejemplo de Android para llamar al método descrito anteriormente:
GetButton.Click += async (sender, e) => {
Task<int> sizeTask = DownloadHomepage();
ResultTextView.Text = "loading...";
ResultEditText.Text = "loading...\n";
// await! control returns to the caller
var intResult = await sizeTask;
// when the Task<int> returns, the value is available and we can display on the UI
ResultTextView.Text = "Length: " + intResult ;
// "returns" void, since it's an event handler
};
Notas:
- El delegado anónimo tiene el prefijo de palabra clave async.
- El método asincrónico DownloadHomepage devuelve un task < int que se almacena en la variable > sizeTask.
- El código espera en la variable sizeTask. Esta es la ubicación en la que se suspende el método y el control se devuelve al código de llamada hasta que la tarea asincrónica finaliza en su propio subproceso.
- La ejecución no se pausa cuando se crea la tarea en la primera línea del método, a pesar de que la tarea se crea allí. La palabra clave await indica la ubicación donde se pausa la ejecución.
- Cuando finaliza la tarea asincrónica, se establece intResult y la ejecución continúa en el subproceso original, desde la línea await.
Llamar a un método asincrónico 2
En la aplicación de ejemplo de iOS, el ejemplo se escribe de forma ligeramente diferente para mostrar un enfoque alternativo. En lugar de usar un delegado anónimo, este ejemplo declara un controlador async de eventos que se asigna como un controlador de eventos normal:
GetButton.TouchUpInside += HandleTouchUpInside;
A continuación, el método del controlador de eventos se define como se muestra aquí:
async void HandleTouchUpInside (object sender, EventArgs e)
{
ResultLabel.Text = "loading...";
ResultTextView.Text = "loading...\n";
// await! control returns to the caller
var intResult = await DownloadHomepage();
// when the Task<int> returns, the value is available and we can display on the UI
ResultLabel.Text = "Length: " + intResult ;
}
Algunos puntos importantes:
- El método se marca como
async, pero devuelvevoid. Normalmente, esto solo se hace para los controladores de eventos (de lo contrario, devolveríaTaskoTask<TResult>). - La palabra clave del método se asigna directamente a una variable ( ) a diferencia del ejemplo anterior, donde se usaba una
awaitvariable intermedia para hacer referencia a laDownloadHomepageintResultTask<int>tarea. Esta es la ubicación donde se devuelve el control al autor de la llamada hasta que el método asincrónico se ha completado en otro subproceso. - Cuando el método asincrónico se completa y devuelve, la ejecución se reanuda en , lo que significa que se devuelve el resultado entero y, a continuación, se
awaitrepresenta en un widget de interfaz de usuario.
Resumen
El uso de async y await simplifica en gran medida el código necesario para generar operaciones de ejecución larga en subprocesos en segundo plano sin bloquear el subproceso principal. También facilita el acceso a los resultados cuando se ha completado la tarea.
En este documento se proporciona información general sobre las nuevas palabras clave del lenguaje y ejemplos para Xamarin.iOS y Xamarin.Android.
Vínculos relacionados
- AsyncWait (ejemplo)
- Devoluciones de llamada como la instrucción Ir a de nuestras generaciones
- Datos (iOS) (ejemplo)
- HttpClient (iOS) (ejemplo)
- MapKitSearch (iOS) (ejemplo)
- Programación asincrónica
- Ajustar una aplicación asincrónica (C#)
- Await, and UI, and deadlocks! ¡Oh mi!
- Procesamiento de tareas a medida que se completan)
- Modelo asincrónico basado en tareas (TAP)
- Asincronía en C# 5 (blog de Eric Lippert): sobre la introducción de las palabras clave
