如何在 CustomMapRenderer - xamarin.forms.maps 中将同步方法更改为异步方法?
How do I change a synchronous method to an asynchronous one in CustomMapRenderer - xamarin.forms.maps?
我从 API 的异步方法中提取数据。
public async Task<IEnumerable<AladinModel>> GetDataFromAPI(string indexOnClick)
{
DateTime dtNow = DateTime.Now;
var dtNowAPI = dtNow.ToString("yyyy-MM-dd");
var listData = new List<AladinModel>();
var result = await _restServiceAPI.GetAladinData(GenerateRequestUri(ConstantsAPI.EndPoint, dtNowAPI, indexOnClick));
foreach (var item in result)
{
var currentData = new AladinModel()
{
Dats = item.Dats,
Ta = item.Ta,
Rh = item.Rh,
Ws = item.Ws,
Rr = item.Rr,
Sr = item.Sr,
Apres = item.Apres
};
listData.Add(currentData);
}
return listData;
}
我想将异步方法传递给另一个同步方法:
CustomPin GetCustomPin(Marker annotation)
{
string addressIndex = annotation.Id.Substring(1);
var result = GetDataFromAPI(addressIndex);
MessagingCenter.Send<object, IEnumerable<AladinModel>>(this, "PinSelected", (IEnumerable<AladinModel>)result);
var position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
foreach (var pin in customPins)
{
if (pin.Position == position)
{
return pin;
}
}
return null;
}
当我尝试将方法更改为异步时:
async CustomPin GetCustomPin(Marker annotation)
我收到错误:
CS1983: The return type of an async method must be void, Task, Task<T>, a task-like type, IAsyncEnumerable<T>, or IAsyncEnumerator<T>
CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
有没有办法使 GetCustomPin
异步方法。
如果没有这个选项,如何让异步接受请求的class变成同步的?
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using static pizhevsoft.Models.ItemsAPI;
namespace pizhevsoft.Services
{
public class RestServiceAPI
{
HttpClient _client;
public RestServiceAPI()
{
_client = new HttpClient();
}
public async Task<List<AladinModel>> GetAladinData(string query)
{
List<AladinModel> weatherData = new List<AladinModel>();
try
{
var response = await _client.GetAsync(query);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
JObject root = JObject.Parse(content);
weatherData = root["aladinModel"][0].ToObject<List<AladinModel>>();
}
}
catch (Exception ex)
{
Debug.WriteLine("\t\tERROR {0}", ex.Message);
}
return weatherData;
}
}
}
例子来自here
=========更新=========
我试图像这样将 GetCustomPin
转换为同步:
async Task<CustomPin> GetCustomPinAsync(Marker annotation)
{
string addressIndex = annotation.Id.Substring(1);
var result = await GetDataFromAPI(addressIndex);
MessagingCenter.Send<object, IEnumerable<AladinModel>>(this, "PinSelected", (IEnumerable<AladinModel>)result);
var position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
foreach (var pin in customPins)
{
if (pin.Position == position)
{
return pin;
}
}
return null;
}
但是现在我在这两种方法中收到错误:
void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
{
var customPin = GetCustomPinAsync(e.Marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (!string.IsNullOrWhiteSpace(customPin.Url))
{
var url = Android.Net.Uri.Parse(customPin.Url);
var intent = new Intent(Intent.ActionView, url);
intent.AddFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
}
}
public Android.Views.View GetInfoContents(Marker marker)
{
var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as Android.Views.LayoutInflater;
if (inflater != null)
{
Android.Views.View view;
var customPin = GetCustomPinAsync(marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (customPin.Name.Equals("Xamarin"))
{
view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
}
else
{
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
}
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}
return view;
}
return null;
}
错误:
/Users/pizhev/Projects/pizhevsoft v3/pizhevsoft/pizhevsoft/pizhevsoft.Android/CustomMapRenderer.cs(54,54): Error CS1061: 'Task<CustomPin>' does not contain a definition for 'Url' and no accessible extension method 'Url' accepting a first argument of type 'Task<CustomPin>' could be found (are you missing a using directive or an assembly reference?) (CS1061) (pizhevsoft.Android)
/Users/pizhev/Projects/pizhevsoft v3/pizhevsoft/pizhevsoft/pizhevsoft.Android/CustomMapRenderer.cs(31,31): Error CS1061: 'Task<CustomPin>' does not contain a definition for 'Name' and no accessible extension method 'Name' accepting a first argument of type 'Task<CustomPin>' could be found (are you missing a using directive or an assembly reference?) (CS1061) (pizhevsoft.Android)
你的GetCustomPin声明错误,应该是
async Task<CustomPin> GetCustomPin(Marker annotation)
{
...
}
and you call like that
CustomPin myCustomPin = await GetCustomPin(annotation)
按照惯例,最好在异步方法后面加上 Async
async Task<CustomPin> GetCustomPinAsync(Marker annotation)
{
...
}
CustomPin myCustomPin = await GetCustomPinAsync(annotation)
如果您无法使 GetInfoContents 异步,也许您可以尝试一下。我不确定当您尝试更新视图时会发生什么,也许您在访问 ui 线程时会遇到问题。
public Android.Views.View GetInfoContents(Marker marker)
{
GetInfoContentsAsync(maker);//you will have a warning here
}
private async Task Android.Views.View GetInfoContentsAsync(Marker marker)
{
var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as Android.Views.LayoutInflater;
if (inflater != null)
{
Android.Views.View view;
var customPin = await GetCustomPinAsync(marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (customPin.Name.Equals("Xamarin"))
{
view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
}
else
{
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
}
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}
return view;
}
return null;
}
我从 API 的异步方法中提取数据。
public async Task<IEnumerable<AladinModel>> GetDataFromAPI(string indexOnClick)
{
DateTime dtNow = DateTime.Now;
var dtNowAPI = dtNow.ToString("yyyy-MM-dd");
var listData = new List<AladinModel>();
var result = await _restServiceAPI.GetAladinData(GenerateRequestUri(ConstantsAPI.EndPoint, dtNowAPI, indexOnClick));
foreach (var item in result)
{
var currentData = new AladinModel()
{
Dats = item.Dats,
Ta = item.Ta,
Rh = item.Rh,
Ws = item.Ws,
Rr = item.Rr,
Sr = item.Sr,
Apres = item.Apres
};
listData.Add(currentData);
}
return listData;
}
我想将异步方法传递给另一个同步方法:
CustomPin GetCustomPin(Marker annotation)
{
string addressIndex = annotation.Id.Substring(1);
var result = GetDataFromAPI(addressIndex);
MessagingCenter.Send<object, IEnumerable<AladinModel>>(this, "PinSelected", (IEnumerable<AladinModel>)result);
var position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
foreach (var pin in customPins)
{
if (pin.Position == position)
{
return pin;
}
}
return null;
}
当我尝试将方法更改为异步时:
async CustomPin GetCustomPin(Marker annotation)
我收到错误:
CS1983: The return type of an async method must be void, Task, Task<T>, a task-like type, IAsyncEnumerable<T>, or IAsyncEnumerator<T>
CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
有没有办法使 GetCustomPin
异步方法。
如果没有这个选项,如何让异步接受请求的class变成同步的?
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using static pizhevsoft.Models.ItemsAPI;
namespace pizhevsoft.Services
{
public class RestServiceAPI
{
HttpClient _client;
public RestServiceAPI()
{
_client = new HttpClient();
}
public async Task<List<AladinModel>> GetAladinData(string query)
{
List<AladinModel> weatherData = new List<AladinModel>();
try
{
var response = await _client.GetAsync(query);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
JObject root = JObject.Parse(content);
weatherData = root["aladinModel"][0].ToObject<List<AladinModel>>();
}
}
catch (Exception ex)
{
Debug.WriteLine("\t\tERROR {0}", ex.Message);
}
return weatherData;
}
}
}
例子来自here =========更新=========
我试图像这样将 GetCustomPin
转换为同步:
async Task<CustomPin> GetCustomPinAsync(Marker annotation)
{
string addressIndex = annotation.Id.Substring(1);
var result = await GetDataFromAPI(addressIndex);
MessagingCenter.Send<object, IEnumerable<AladinModel>>(this, "PinSelected", (IEnumerable<AladinModel>)result);
var position = new Position(annotation.Position.Latitude, annotation.Position.Longitude);
foreach (var pin in customPins)
{
if (pin.Position == position)
{
return pin;
}
}
return null;
}
但是现在我在这两种方法中收到错误:
void OnInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
{
var customPin = GetCustomPinAsync(e.Marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (!string.IsNullOrWhiteSpace(customPin.Url))
{
var url = Android.Net.Uri.Parse(customPin.Url);
var intent = new Intent(Intent.ActionView, url);
intent.AddFlags(ActivityFlags.NewTask);
Android.App.Application.Context.StartActivity(intent);
}
}
public Android.Views.View GetInfoContents(Marker marker)
{
var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as Android.Views.LayoutInflater;
if (inflater != null)
{
Android.Views.View view;
var customPin = GetCustomPinAsync(marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (customPin.Name.Equals("Xamarin"))
{
view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
}
else
{
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
}
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}
return view;
}
return null;
}
错误:
/Users/pizhev/Projects/pizhevsoft v3/pizhevsoft/pizhevsoft/pizhevsoft.Android/CustomMapRenderer.cs(54,54): Error CS1061: 'Task<CustomPin>' does not contain a definition for 'Url' and no accessible extension method 'Url' accepting a first argument of type 'Task<CustomPin>' could be found (are you missing a using directive or an assembly reference?) (CS1061) (pizhevsoft.Android)
/Users/pizhev/Projects/pizhevsoft v3/pizhevsoft/pizhevsoft/pizhevsoft.Android/CustomMapRenderer.cs(31,31): Error CS1061: 'Task<CustomPin>' does not contain a definition for 'Name' and no accessible extension method 'Name' accepting a first argument of type 'Task<CustomPin>' could be found (are you missing a using directive or an assembly reference?) (CS1061) (pizhevsoft.Android)
你的GetCustomPin声明错误,应该是
async Task<CustomPin> GetCustomPin(Marker annotation)
{
...
}
and you call like that
CustomPin myCustomPin = await GetCustomPin(annotation)
按照惯例,最好在异步方法后面加上 Async
async Task<CustomPin> GetCustomPinAsync(Marker annotation)
{
...
}
CustomPin myCustomPin = await GetCustomPinAsync(annotation)
如果您无法使 GetInfoContents 异步,也许您可以尝试一下。我不确定当您尝试更新视图时会发生什么,也许您在访问 ui 线程时会遇到问题。
public Android.Views.View GetInfoContents(Marker marker)
{
GetInfoContentsAsync(maker);//you will have a warning here
}
private async Task Android.Views.View GetInfoContentsAsync(Marker marker)
{
var inflater = Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService) as Android.Views.LayoutInflater;
if (inflater != null)
{
Android.Views.View view;
var customPin = await GetCustomPinAsync(marker);
if (customPin == null)
{
throw new Exception("Custom pin not found");
}
if (customPin.Name.Equals("Xamarin"))
{
view = inflater.Inflate(Resource.Layout.XamarinMapInfoWindow, null);
}
else
{
view = inflater.Inflate(Resource.Layout.MapInfoWindow, null);
}
var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
var infoSubtitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);
if (infoTitle != null)
{
infoTitle.Text = marker.Title;
}
if (infoSubtitle != null)
{
infoSubtitle.Text = marker.Snippet;
}
return view;
}
return null;
}