任务异步调用不返回会导致死锁

罗恩

我是C#的新手,所以这很容易。我正忙于创建xamarin表单应用程序,并且需要UI上下一页的数据。它的标签页,所有3个页面都需要基类将返回的信息。我遇到的问题是我需要致电google api服务获取公司信息。因此,我创建了一个异步调用。因此现在代码由于此而返回。由于选项卡式页面,我需要将数据绑定到屏幕上,现在我需要等待数据,因此基本上需要它是同步的。

我已经尽力在该主题上找到了一切。也许我这样做的方式是错误的,但希望我的代码能证明这一点。

这是选项卡式页面:

    public BusinessTabbedPage(string PlaceId)
    {
        Children.Add(new BusinessSpecialsPage(PlaceId));
        InitializeComponent();
    }

这将是应用程序上调用viewmodel的页面之一

    public BusinessSpecialsPage(string PlaceId)
    {
        BindingContext = new BusinessSpecialsPageViewModel(PlaceId);
        InitializeComponent();
    }

由于3个页面需要相同的数据,因此我创建了一个基类。这将获取数据并将所有内容传递回UI。

    public BusinessBaseViewModel(string placeId)
    {
        Task<List<CompanyProfileModel>> task = GBDFromGoogle(placeId);
        task.Wait();
    }

    public async Task<List<CompanyProfileModel>> GBDFromGoogle(string PlaceId)
    {
        var info = await ApiGoogle.GetGoogleCompanySelectedDetails(PlaceId);
        var Companyresult = info.result;

        CompanyProfileModel CompList = new CompanyProfileModel
        {
            ContactDetails = Companyresult.formatted_phone_number,
            Name = Companyresult.name,
            Website = Companyresult.website,
        };
        ComPF.Add(CompList);

        return ComPF;
    }

我认为这是api调用,正在添加一个新任务,然后进程死锁?

    public static async Task<GoogleSelectedPlaceDetails> GGCSD(string place_id)
    {
        GoogleSelectedPlaceDetails results = null;

        var client = new HttpClient();
        var passcall = "https://maps.googleapis.com/maps/api/place/details/json?placeid=" + place_id + "&key=" + Constants.GoogleApiKey;
        var json = await client.GetStringAsync(passcall);
        //results = await Task.Run(() => JsonConvert.DeserializeObject<GoogleSelectedPlaceDetails>(json)).ConfigureAwait(false);
        results = JsonConvert.DeserializeObject<GoogleSelectedPlaceDetails>(json);

        return results;
    }

我需要避免僵局的过程。它需要等待任务完成,这样我才能将数据返回到屏幕。

伊斯玛

Task.Wait 会阻塞当前线程,因此您永远不要在Xamarin应用程序中使用它,甚至不要在构造函数中使用它,否则,您的应用程序将冻结,直到您收到一些数据,如果服务关闭或用户失去连接,这些数据可能永远不会发生。

除了在ViewModel的构造函数中调用数据外,还可以在视图Appearing事件时对其进行初始化ContentPage

为此,您可以创建自定义行为,甚至可以做得更好,可以使用以下已经为您完成此操作的库:

使用NuGet: Install-Package Behaviors.Forms -Version 1.4.0

安装库后,可以使用将EventHandlerBehavior事件关联到ViewModel命令,例如:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:behaviors="clr-namespace:Behaviors;assembly=Behaviors"
             xmlns:viewModels="clr-namespace:YourApp.ViewModels"
             Title="Business Page"
             x:Class="YourApp.Views.BusinessPage">

    <ContentPage.BindingContext>
        <viewModels:BusinessViewModel />
    </ContentPage.BindingContext>

    <ContentPage.Behaviors>
        <behaviors:EventHandlerBehavior EventName="Appearing">
            <behaviors:InvokeCommandAction Command="{Binding AppearingCommand}" />
        </behaviors:EventHandlerBehavior>
    </ContentPage.Behaviors>

    [...]

ViewModel:

public BusinessBaseViewModel(string placeId)
{
    AppearingCommand = new Command(Appearing);
    PlaceId = placeId;
}

public ICommand AppearingCommand { get; private set; }

public string PlaceId { get; private set; }

private ObservableCollection<CompanyProfileModel> _googleGbd;
public ObservableCollection GoogleGbd
{
    get { _googleGbd?? (_googleGbd = new ObservableCollection<CompanyProfileModel>()); };
    set 
    {
         if (_googleGdb != value)
         {
             _googleGdb = value;
             NotifyPropertyChanged();
         }
    }
}

private async void Appearing()
{
    var companyResult = await ApiGoogle.GetGoogleCompanySelectedDetails(PlaceId);

    CompanyProfileModel companyProfile = new CompanyProfileModel
    {
        ContactDetails = companyResult.formatted_phone_number,
        Name = companyResult.name,
        Website = companyResult.website,
    };
    GoogleGbd.Add(companyProfile);
}

如果只希望在视图第一次出现时加载数据,则可以添加一个bool标志来知道您已经加载了数据。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如果不一定要在其他线程上执行异步调用,阻塞异步调用怎么会导致死锁?

异步等待导致死锁

从异步方法中,是否正在调用LINQ查询的ToList,而不是ToListAsync,这可能会导致死锁?

异步调用cuda()会导致SyntaxError

导致死锁的异步/等待示例

多任务调度导致死锁

重用Go通道会导致死锁

为什么在Windows Service中阻止异步会导致死锁?

JerseyClient异步调用似乎会导致线程挂起

for循环导致死锁

为什么此异步/等待代码不会导致死锁?

为什么此控制台应用程序中的异步等待模式会导致死锁?

在MVC中从同步调用异步而没有等待时,TPL任务死锁

丢弃过滤的统计信息会导致死锁

在systemd服务内部启动systemd服务会导致死锁

此“同步”代码会导致死锁吗?

Oracle 表上的共享索引是否会导致死锁?

在循环内,是否使用任务的continuewith将每个异步调用链接到返回的任务?

调用ExecuteAsync()函数时异步任务死锁

在路由中导航时,useEffect() 函数内的 Firestore 异步调用会导致错误

C#httpClient(阻止异步调用)死锁

在Firebird脚本中创建表会导致死锁导致“元数据更新失败”

调用onDestroy后返回异步调用

来自GoogleAuthUtil(Android中的Google Plus集成)的“从主线程调用此代码可能会导致死锁和/或ANR,同时获取accesToken”。

两个并发但相同的DELETE语句会导致死锁吗?

为什么以不同顺序解锁两个锁定的银行帐户会导致死锁?

为什么在Golang中发送大于缓冲通道大小的值会导致死锁错误?

在同一互斥锁上使用两个std :: unique_lock会导致死锁?

为什么在同一goroutine中使用未缓冲的通道会导致死锁?