Xamarin Async метод не работает, перемещая его в свой собственный класс
Я пытаюсь очистить свой код и поместить вещи в классы (что-то, что я должен был сделать с самого начала, я знаю). Но я сталкиваюсь с проблемой с async
Task
,
У меня есть следующее async
Метод, который изначально находился в том же классе, что и вызов этого метода, т.е. не нужно создавать экземпляры, я просто вызвал метод, он работал асинхронно, и все работало нормально.
Тем не менее, я теперь перенес это async
метод нового класса, где я собираюсь разместить все методы, относящиеся к базе данных. Итак, теперь я создаю экземпляр нового класса и вызываю метод, но он, кажется, зависает и никуда не денется.
Вот новый класс с методом asnyc:
public class ParseDBQuery
{
public string DBcompanyName { get; set; }
public string DBofferTitle { get; set; }
public string DBlatitude { get; set; }
public string DBlongitude { get; set; }
public string DBofferDescription { get; set; }
public string DBlogoURL { get; set; }
public async Task getUserCoupons()
{
try{
var query = ParseObject.GetQuery("userCoupons").WhereEqualTo("userObjectID", ParseUser.CurrentUser).Include("couponsObjectID");
IEnumerable<ParseObject> MyResults = await query.FindAsync();
foreach (var result in MyResults)
{
var couponObject = result.Get<ParseObject>("couponsObjectID");
DBcompanyName = couponObject.Get<string>("entityName");
Console.WriteLine ("The company name is......... " + DBcompanyName);
DBofferTitle = couponObject.Get<string>("offerTitle");
Console.WriteLine ("The offer title is......... " + DBofferTitle);
DBofferDescription = couponObject.Get<string>("offerDescription");
Console.WriteLine ("The offer title is......... " + DBofferDescription);
DBlogoURL = couponObject.Get<string>("logoURL");
Console.WriteLine ("The logo URL is......... " + DBlogoURL);
DBlatitude = couponObject.Get<string>("latitude");
Console.WriteLine ("The latitude is......... " + DBlatitude);
DBlongitude = couponObject.Get<string>("longitude");
Console.WriteLine ("The longitude is......... " + DBlongitude);
}
}
catch (ParseException e) {
Console.WriteLine ("There was a problem fetching getUserCoupon data from parse - ParseDBQuery class");
}
}
}
Вот инстанцирование и вызов метода:
ParseDBQuery myQuery = new ParseDBQuery ();
Task myTask = myQuery.getUserCoupons ();
//myTask.Wait ();
Здесь вы можете увидеть, что я попробовал Wait()
метод, и это где он останавливается. Если я удалю Wait()
метод, код продолжается до получения значений из async
метод (очевидно, из-за await
). Проблема, кажется, в новом классе, где метод теперь живет. Если я поставлю точку останова на один из запросов, таких как
DBcompanyName = couponObject.Get<string>("entityName");
... это никогда не достигнет точки останова. Так что проблема где-то здесь, но я не знаю почему.
Странно, если я просто помещу весь метод обратно в тот же класс, что и вызов метода, без создания экземпляра, он работает отлично! Есть идеи?
1 ответ
Это общая тупиковая ситуация, которую я описываю в своем блоге.
Когда async
метод ожидает задачу, по умолчанию await
будет захватывать "текущий контекст" и использовать его для возобновления async
метод. В этом случае этот контекст является контекстом пользовательского интерфейса, который связан с одним потоком пользовательского интерфейса. Когда ваш код блокирует задачу (вызывая Wait
), он блокирует поток пользовательского интерфейса. Когда FindAsync
задача завершена, async
getUserCoupons
метод пытается возобновить работу в потоке пользовательского интерфейса, но не может этого сделать, потому что поток пользовательского интерфейса заблокирован.
Кроме того, он работает, когда код находится в классе Main (когда ваш код предположительно вызывается Wait
на задание вернулось из FindAsync
) так как FindAsync
не возобновляется в захваченном контексте.
Идеальным решением является использование await
вместо Wait
, Это означает, что вызов метода getUserCoupons
должен стать async
и его вызывающий должен использовать await
и стать async
и тд и тп. Это рост async
совершенно естественно и должно быть принято. В идеале вы хотите идти "асинхронно до конца"; Я опишу эту концепцию больше в статье MSDN.