GetObject <T> de Akavache se bloquea cuando se espera. Alguna idea de lo que está mal aquí?
Tengo una aplicación Xamarin.Forms, con este código en mi clase App (sí, esto es sólo un ejemplo para demostrar el problema):
public App() { BlobCache.ApplicationName = "MyApp"; BlobCache.EnsureInitialized(); // The root page of your application MainPage = GetMainPage(); } public object BlockingGetExternalUser() { return GetExternalUser().Result; } private async Task<object> GetExternalUser() { try { return await BlobCache.LocalMachine.GetObject<object>("user"); } catch (KeyNotFoundException) { return null; } }
La clave "usuario" no existe, por lo que esperaría obtener una KeyNotFoundException. Sin embargo nunca veo esta excepción ser lanzada. En su lugar simplemente "se bloquea" y nunca vuelve de la llamada GetObject esperar.
- System.TypeLoadException: No se pudo resolver el tipo con el token 01000019
- Xamarin Forms ToolBarItem (Número sobre el icono) Notificación
- No puedo ejecutar la aplicación después de actualizar Xamarin.Forms
- Cómo utilizar controles Xamarin.Form y controles nativos En la misma página
- Xamarin Android Crash en Inicio "Got a SIGSEGV"
Estoy ejecutando esto en mi teléfono con Android 5.0.
Alguna idea de cómo solucionar este problema? ¿Estoy haciendo algo fundamentalmente equivocado?
Actualización: En una nota lateral: En lugar de intentar inmediatamente GetObject, se podría intentar comprobar si la clave realmente existe en la caché y sólo entonces recuperarla de la caché. Sin embargo, si no me equivoco, no hay otra forma de hacer un cheque que no sea llamar a GetObject y capturar la excepción como en la muestra anterior. Para un escenario en el que uno sólo desearía saber si existe un artículo, eso no parece ser el ideal. Tal vez un "Exists ()" método sería un buen tener en Akavache? O tal vez me falta algo?
Actualización2: Cambiar el ejemplo para no utilizar un método asíncrono en el constructor. Sólo para demostrar un punto de que ese no es el problema.
Actualización3: Eliminar la llamada del constructor. Cuando llamo a BlockingGetExternalUser desde cualquier parte de mi código, el await seguirá colgando.
- Xamarin.Forms: El receptor de difusión no funciona cuando la aplicación está cerrada
- Quitar icono de la barra de acción xamarin
- Xamarin Android con multidex - error en modo de depuración
- Cómo reducir el tamaño de código de usuario para una aplicación Xamarin Forms en Visual Studio 2015?
- Xamarin.Droid causando errores de compilación en Visual Studio 2015 cuando se utiliza Xamarin.Forms
- ¿Por qué Xamarin.Forms es tan lento al mostrar algunas etiquetas (especialmente en Android)?
- Cómo generar un archivo .apk de Xamarin.Forms proyecto utilizando Visual Studio?
- Cómo obtener / detectar el tamaño de la pantalla en Xamarin.Forms?
Lo más seguro es que tienes un bloqueo. Citar Esperando sincrónicamente una operación asíncrona y por qué Wait () congela el programa aquí :
La espera dentro de su método asíncrono está tratando de volver al hilo de interfaz de usuario.
Dado que el hilo de la interfaz de usuario está ocupado esperando que se complete toda la tarea, tiene un bloqueo.
Tenga en cuenta que su llamada a .Result
implica un Task.Wait()
alguna parte.
Hay dos soluciones: Evite completamente los métodos async
o envuelva el código en una Task.Run
siguiente manera:
public object BlockingGetExternalUser() { return Task.Run<object>(() => GetExternalUser().Result); }
(Espero que esté compilando no verifiqué en VS 🙂
Por experiencia tiendo a evitar los métodos async
en combinación con SQLite en estos días. La razón es que la mayoría de las bibliotecas de wrapper de SQLite utilizan el Task.Run
Anti-patrón de Task.Run
para proporcionar wrappers async
alrededor de sus métodos mientras que SQLite no tiene ninguna anotación intrínseca de ser asíncrono. Tenga en cuenta que está perfectamente bien para que envuelva las cosas en Task.Run
para hacerlas asíncronas y que es sólo un anti-patrón para los diseñadores de la biblioteca, lo que sugiere a sus usuarios que los métodos son asíncronos cuando en realidad no lo son. Puedes leer más sobre esto aquí: Task.Run como un anti-patrón?
El uso de métodos asíncronos en un constructor ( var externalUser = GetExternalUser().Result;
) se considera como un código incorrecto. No debe utilizar métodos asíncronos en los constructores de una clase. Lea esto: ¿Pueden los constructores ser asíncronos?
Puede intentar cambiarlo para evitar bloqueos:
Func<Task> task = async () => { await GetExternalUser().ConfigureAwait(false); }; task().Wait();
… pero no lo recomiendo.
- Fragmento de acceso del adaptador
- Android – Cómo comprobar si la opción de desarrollador está habilitada