如何在 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;
    }