Phoneswapshop Phoneswapshop - 6 months ago 142
JSON Question

Xamarin forms android json - Async call hangs/never returns

Hello I'm working on a android app in Xamarin forms thats getting json data from a service and its supposed to display that data in The ContactInfo class however when you click on the button that's supposed to get that data and then display it and then take you to the ContactInfo class it hangs and after a minute my galaxy s7 tells me that app isn't responding would you like to close it?
I have no idea what i'm doing wrong

here's my 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>


Here's my codebehind:

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



}
}
}


any help would be amazing!

Thank in advance!

Answer

Try moving the async code out of the constructor. A common approach to this is to override OnAppearing() to perform the work. You would also probably want to display an ActivityIndicator in your UI until the data has been loaded:

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);
    }
}

To fix the binding problem, recognize that you are assigning the list itself to your page's BindingContext. You can do one of two things:

  1. Change ItemsSource="{Binding ContactInfoList}" in your ListView XAML to ItemsSource="{Binding .}".
  2. Change this.BindingContext = ContactInfoList; in your constructor to this.BindingContext = this;.

Option #1 is preferred.

Comments