Xamarin 表单 android json - 异步调用 hangs/never returns
Xamarin forms android json - Async call hangs/never returns
你好,我正在开发 Xamarin 表单中的 android 应用程序,它从服务中获取 json 数据,并且它应该在 ContactInfo class 中显示该数据,但是当你单击应该获取该数据的按钮,然后显示它,然后将您带到 ContactInfo class 它挂起,一分钟后我的 galaxy s7 告诉我该应用程序没有响应你想关闭它吗?
我不知道我做错了什么
这是我的 Xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ReadyMo.ContactInfo">
<ListView ItemsSource="{Binding ContactInfoList}" HasUnevenRows="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame Padding="0,0,0,8" BackgroundColor="#d2d5d7">
<Frame.Content>
<Frame Padding="15,15,15,15" OutlineColor="Gray" BackgroundColor="White">
<Frame.Content>
<StackLayout Padding="20,0,0,0" Orientation="Horizontal" HorizontalOptions="CenterAndExpand">
<Label x:Name="FirstName" Text="{Binding First_Name}" HorizontalOptions="Center">
</Label>
<Label x:Name ="LastName" Text="{Binding Last_Name}" HorizontalOptions="Center">
</Label>
<Label x:Name="County" Text="{Binding name}" HorizontalOptions="Center">
</Label>
<Label x:Name ="Adress" Text="{Binding Address1}" HorizontalOptions="Center">
</Label>
<Label x:Name ="City" Text="{Binding Address2}" HorizontalOptions="Center">
</Label>
<Label x:Name="Number" Text="{Binding BusinessPhone}" HorizontalOptions="Center">
</Label>
</StackLayout>
</Frame.Content>
</Frame>
</Frame.Content>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
这是我的代码隐藏:
using Newtonsoft.Json;
using ReadyMo.Data;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace ReadyMo
{
public partial class ContactInfo : ContentPage
{
private County item;
public static async Task<string> GetContactString(string contactid)
{
HttpClient client = new HttpClient();
var url = $"http://sema.dps.mo.gov/county/service.php?id={contactid}";
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var responsetext = await response.Content.ReadAsStringAsync();
return responsetext;
}
throw new Exception(response.ReasonPhrase);
}
public ContactInfo()
{
InitializeComponent();
}
List <ContactInfoModel> ContactInfoList;
public ContactInfo(County item)
{
InitializeComponent();
this.item = item;
var contactpagetext = ContactManager.GetContactString(item.id);
var contact = GetContactString("001").Result;
//need to add update database code
//Convert Jason string to object
ContactInfoList = JsonConvert.DeserializeObject<List<ContactInfoModel>>(contact);
this.BindingContext = ContactInfoList;
//Floodplain Administrators
}
}
}
任何帮助都会很棒!
提前致谢!
您的问题出在这一行:
var contact = GetContactString("001").Result;
causing a deadlock我在博客上详细解释了。
要解决此问题,您必须首先意识到 UI 必须 立即显示 。当 OS 调用您的代码时,您不能等待 HTTP 请求完成后再响应;那是不允许的。
您可以做的是启动 HTTP 请求并显示其他内容(如微调器或"loading..." 消息)立即地。然后,当 HTTP 请求完成时,用新信息更新您的显示。
我的 MSDN article on async MVVM data binding 中有更多详细信息和示例代码。
尝试将异步代码移出构造函数。一种常见的方法是覆盖 OnAppearing()
来执行工作。您可能还想在 UI 中显示一个 ActivityIndicator
,直到数据加载完毕:
public partial class ContactInfo : ContentPage
{
private County item;
public static async Task<string> GetContactString(string contactid)
{
HttpClient client = new HttpClient();
var url = $"http://sema.dps.mo.gov/county/service.php?id={contactid}";
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var responsetext = await response.Content.ReadAsStringAsync();
return responsetext;
}
throw new Exception(response.ReasonPhrase);
}
public ContactInfo()
{
InitializeComponent();
ContactInfoList = new ObservableCollection<ContactInfoModel>();
}
ObservableCollection<ContactInfoModel> ContactInfoList;
public ContactInfo(County item) : this()
{
this.item = item;
this.BindingContext = ContactInfoList;
}
protected override async void OnAppearing ()
{
if (item == null)
return;
var contact = await GetContactString(item.id);
var models = JsonConvert.DeserializeObject<List<ContactInfoModel>>(contact);
foreach (var model in models)
ContactInfoList.Add(model);
}
}
要解决绑定问题,请认识到您正在将列表本身分配给页面的 BindingContext。您可以执行以下两项操作之一:
- 将 ListView XAML 中的
ItemsSource="{Binding ContactInfoList}"
更改为 ItemsSource="{Binding .}"
。
- 将构造函数中的
this.BindingContext = ContactInfoList;
更改为 this.BindingContext = this;
。
首选选项 #1。
你好,我正在开发 Xamarin 表单中的 android 应用程序,它从服务中获取 json 数据,并且它应该在 ContactInfo class 中显示该数据,但是当你单击应该获取该数据的按钮,然后显示它,然后将您带到 ContactInfo class 它挂起,一分钟后我的 galaxy s7 告诉我该应用程序没有响应你想关闭它吗? 我不知道我做错了什么
这是我的 Xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ReadyMo.ContactInfo">
<ListView ItemsSource="{Binding ContactInfoList}" HasUnevenRows="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame Padding="0,0,0,8" BackgroundColor="#d2d5d7">
<Frame.Content>
<Frame Padding="15,15,15,15" OutlineColor="Gray" BackgroundColor="White">
<Frame.Content>
<StackLayout Padding="20,0,0,0" Orientation="Horizontal" HorizontalOptions="CenterAndExpand">
<Label x:Name="FirstName" Text="{Binding First_Name}" HorizontalOptions="Center">
</Label>
<Label x:Name ="LastName" Text="{Binding Last_Name}" HorizontalOptions="Center">
</Label>
<Label x:Name="County" Text="{Binding name}" HorizontalOptions="Center">
</Label>
<Label x:Name ="Adress" Text="{Binding Address1}" HorizontalOptions="Center">
</Label>
<Label x:Name ="City" Text="{Binding Address2}" HorizontalOptions="Center">
</Label>
<Label x:Name="Number" Text="{Binding BusinessPhone}" HorizontalOptions="Center">
</Label>
</StackLayout>
</Frame.Content>
</Frame>
</Frame.Content>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
这是我的代码隐藏:
using Newtonsoft.Json;
using ReadyMo.Data;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace ReadyMo
{
public partial class ContactInfo : ContentPage
{
private County item;
public static async Task<string> GetContactString(string contactid)
{
HttpClient client = new HttpClient();
var url = $"http://sema.dps.mo.gov/county/service.php?id={contactid}";
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var responsetext = await response.Content.ReadAsStringAsync();
return responsetext;
}
throw new Exception(response.ReasonPhrase);
}
public ContactInfo()
{
InitializeComponent();
}
List <ContactInfoModel> ContactInfoList;
public ContactInfo(County item)
{
InitializeComponent();
this.item = item;
var contactpagetext = ContactManager.GetContactString(item.id);
var contact = GetContactString("001").Result;
//need to add update database code
//Convert Jason string to object
ContactInfoList = JsonConvert.DeserializeObject<List<ContactInfoModel>>(contact);
this.BindingContext = ContactInfoList;
//Floodplain Administrators
}
}
}
任何帮助都会很棒!
提前致谢!
您的问题出在这一行:
var contact = GetContactString("001").Result;
causing a deadlock我在博客上详细解释了。
要解决此问题,您必须首先意识到 UI 必须 立即显示 。当 OS 调用您的代码时,您不能等待 HTTP 请求完成后再响应;那是不允许的。
您可以做的是启动 HTTP 请求并显示其他内容(如微调器或"loading..." 消息)立即地。然后,当 HTTP 请求完成时,用新信息更新您的显示。
我的 MSDN article on async MVVM data binding 中有更多详细信息和示例代码。
尝试将异步代码移出构造函数。一种常见的方法是覆盖 OnAppearing()
来执行工作。您可能还想在 UI 中显示一个 ActivityIndicator
,直到数据加载完毕:
public partial class ContactInfo : ContentPage
{
private County item;
public static async Task<string> GetContactString(string contactid)
{
HttpClient client = new HttpClient();
var url = $"http://sema.dps.mo.gov/county/service.php?id={contactid}";
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var responsetext = await response.Content.ReadAsStringAsync();
return responsetext;
}
throw new Exception(response.ReasonPhrase);
}
public ContactInfo()
{
InitializeComponent();
ContactInfoList = new ObservableCollection<ContactInfoModel>();
}
ObservableCollection<ContactInfoModel> ContactInfoList;
public ContactInfo(County item) : this()
{
this.item = item;
this.BindingContext = ContactInfoList;
}
protected override async void OnAppearing ()
{
if (item == null)
return;
var contact = await GetContactString(item.id);
var models = JsonConvert.DeserializeObject<List<ContactInfoModel>>(contact);
foreach (var model in models)
ContactInfoList.Add(model);
}
}
要解决绑定问题,请认识到您正在将列表本身分配给页面的 BindingContext。您可以执行以下两项操作之一:
- 将 ListView XAML 中的
ItemsSource="{Binding ContactInfoList}"
更改为ItemsSource="{Binding .}"
。 - 将构造函数中的
this.BindingContext = ContactInfoList;
更改为this.BindingContext = this;
。
首选选项 #1。