Xamarin.Forms 中的死锁
Posted
技术标签:
【中文标题】Xamarin.Forms 中的死锁【英文标题】:Deadlock in Xamarin.Forms 【发布时间】:2020-06-06 21:56:34 【问题描述】:我的 Xamarin 应用程序出现问题。该应用程序对我的网站使用自定义 API。我对async/await
方法没有太多经验。
以下代码显示了 App.xaml.cs:
public partial class App : Application
public static bool IsUserLoggedIn get; set;
public static UserModel currentLoggedInUser get; set;
public static List<ActionTypeModel> listTypes;
public static List<ActionSubTypeModel> listSubtypes;
public static List<UserModel> listFriends;
public static List<List<ActionModel>> listActiveActions;
public static List<ActionModel> listLastAction;
public App()
this.InitializeComponent();
APIHelper.InitializeClient();
StartApp().Wait();
private async Task StartApp()
//// DEBUG
//MyAccountStorage.Logout();
string username = await MyAccountStorage.GetUsername().ConfigureAwait(false);
string password = await MyAccountStorage.GetPassword().ConfigureAwait(false);
string user_id = await MyAccountStorage.GetId().ConfigureAwait(false);
if (username != null && password != null)
currentLoggedInUser = new UserModel();
if (user_id != null)
currentLoggedInUser.user_id = Convert.ToInt32(user_id);
currentLoggedInUser.username = username;
currentLoggedInUser.password = password;
bool isValid = false;
isValid = await AreCredentialsCorrect(0, currentLoggedInUser.username, currentLoggedInUser.password).ConfigureAwait(false);
if (isValid)
IsUserLoggedIn = true;
await FillLists().ConfigureAwait(false);
MainPage = new NavigationPage(await MyPage.BuildMyPage().ConfigureAwait(false));
else
IsUserLoggedIn = false;
MainPage = new NavigationPage(await LoginPage.BuildLoginPage().ConfigureAwait(false));
else
IsUserLoggedIn = false;
MainPage = new NavigationPage(await LoginPage.BuildLoginPage().ConfigureAwait(false));
private async Task FillLists()
listFriends = await DataControl.GetFriends(App.currentLoggedInUser.user_id, App.currentLoggedInUser.username, App.currentLoggedInUser.password).ConfigureAwait(false);
if (listFriends == null)
listFriends = new List<UserModel>();
listTypes = await DataControl.GetTypes(App.currentLoggedInUser.username, App.currentLoggedInUser.password).ConfigureAwait(false);
if (listTypes == null)
listTypes = new List<ActionTypeModel>();
listActiveActions = new List<List<ActionModel>>();
for (int i = 0; i < listTypes.Count; i++)
listActiveActions.Add(await DataControl.GetActiveActions(listTypes[i].action_type_id, currentLoggedInUser.user_id, currentLoggedInUser.username, currentLoggedInUser.password).ConfigureAwait(false));
listSubtypes = await DataControl.GetSubtypes(App.currentLoggedInUser.username, App.currentLoggedInUser.password).ConfigureAwait(false);
if (listSubtypes == null)
listSubtypes = new List<ActionSubTypeModel>();
listLastAction = await DataControl.GetLastAction(App.currentLoggedInUser.user_id, App.currentLoggedInUser.username, App.currentLoggedInUser.password).ConfigureAwait(false);
if (listLastAction == null)
listLastAction = new List<ActionModel>();
public static async Task<bool> AreCredentialsCorrect(int type, string user, string pass, string nick = "", string email = "")
List<UserModel> listUsers;
if (type == 1)
listUsers = await DataControl.CheckCredentials(1, user, pass, nick, email).ConfigureAwait(false);
else
listUsers = await DataControl.CheckCredentials(0, user, pass).ConfigureAwait(false);
if (listUsers != null)
if (listUsers.Any())
currentLoggedInUser = listUsers.First();
currentLoggedInUser.password = pass;
return true;
return false;
我在 DataControl.cs 中有 API:
public static async Task<List<UserModel>> CheckCredentials(int type, string username, string pass, string email = "", string nickname = "")
string password = APIHelper.GetHashSha256(pass);
string url = string.Empty;
if (type == 0)
url = APIHelper.ApiClient.BaseAddress + "/account/login.php?username=" + username + "&password=" + password;
if (type == 1)
string nick = string.Empty;
if (string.IsNullOrEmpty(nickname) == false)
nick = "&nickname=" + nickname;
url = APIHelper.ApiClient.BaseAddress + "/account/signup.php?username=" + username + "&password=" + password + "&email=" + email + nick;
if (string.IsNullOrEmpty(url))
return null;
using (HttpResponseMessage response = await APIHelper.ApiClient.GetAsync(url).ConfigureAwait(false))
if (response.IsSuccessStatusCode)
List<UserModel> listUsers = JsonConvert.DeserializeObject<List<UserModel>>(await response.Content.ReadAsStringAsync().ConfigureAwait(false));
return listUsers;
else
return null;
这是不同的async
方法之一。当我遗漏ConfigureAwait(false)
时,我遇到了死锁。当我将它添加到代码中时,我遇到了错误。
你能帮帮我吗?
【问题讨论】:
When I leave out the "ConfigureAwait(false)" I run into a deadlock
- 这强烈表明你在某个地方是blocking on async。例如在您的constructor 中的StartApp().Wait();
。不要这样做。
App 构造函数是我使用 Wait() 方法的唯一位置。其他所有方法都是异步的,并使用 await 来调用。
是的,一个就够了。
如果我删除 Wait() 应用程序什么也不做,我在调试输出中看到一个无穷无尽的线程池启动行和线程池完成...
您不能使用构造函数中的异步函数。您不仅需要删除Wait
(这会导致fire-and-forget),还需要重新构建程序,以免从构造函数中调用异步方法。
【参考方案1】:
您可以使用Task.Run(
//call your async method here
);
所以在你的情况下:
Task.Run(Startup);
【讨论】:
以上是关于Xamarin.Forms 中的死锁的主要内容,如果未能解决你的问题,请参考以下文章
ScrollView 问题中的 Xamarin.Forms 捏手势
Xamarin.Forms.Forms.Init(e) Onlaunched 中的 FileNotFoundExeception
ReactiveUI 中的 Xamarin.Forms 控件是不是需要自定义绑定?