Reputation: 1237
First some context, I've been fooling around with Xamarin and API data from HERE.
My Current Solution structure is as follows:
Main View looks as follows:
DataModel.cs
is as follows:
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using J = Newtonsoft.Json.JsonPropertyAttribute;
namespace CrossPlatformTFL.Model
{
public partial class DataModel
{
[J("disruptions")] public List<object> Disruptions { get; set; }
[J("modified")] public string Modified { get; set; }
[J("created")] public string Created { get; set; }
[J("$type")] public string Type { get; set; }
[J("crowding")] public Crowding Crowding { get; set; }
[J("lineStatuses")] public List<LineStatus> LineStatuses { get; set; }
[J("id")] public string Id { get; set; }
[J("modeName")] public string ModeName { get; set; }
[J("routeSections")] public List<RouteSection> RouteSections { get; set; }
[J("name")] public string Name { get; set; }
[J("serviceTypes")] public List<ServiceType> ServiceTypes { get; set; }
}
public partial class Crowding
{
[J("$type")] public string Type { get; set; }
}
public partial class LineStatus
{
[J("id")] public long Id { get; set; }
[J("created")] public string Created { get; set; }
[J("$type")] public string Type { get; set; }
[J("disruption")] public Disruption Disruption { get; set; }
[J("reason")] public string Reason { get; set; }
[J("statusSeverityDescription")] public string StatusSeverityDescription { get; set; }
[J("lineId")] public string LineId { get; set; }
[J("statusSeverity")] public long StatusSeverity { get; set; }
[J("validityPeriods")] public List<ValidityPeriod> ValidityPeriods { get; set; }
}
public partial class Disruption
{
[J("affectedStops")] public List<AffectedStop> AffectedStops { get; set; }
[J("created")] public string Created { get; set; }
[J("additionalInfo")] public string AdditionalInfo { get; set; }
[J("$type")] public string Type { get; set; }
[J("affectedRoutes")] public List<AffectedRoute> AffectedRoutes { get; set; }
[J("categoryDescription")] public string CategoryDescription { get; set; }
[J("category")] public string Category { get; set; }
[J("closureText")] public string ClosureText { get; set; }
[J("isBlocking")] public bool? IsBlocking { get; set; }
[J("description")] public string Description { get; set; }
[J("isWholeLine")] public bool? IsWholeLine { get; set; }
}
public partial class AffectedStop
{
[J("lat")] public long Lat { get; set; }
[J("commonName")] public string CommonName { get; set; }
[J("$type")] public string Type { get; set; }
[J("id")] public string Id { get; set; }
[J("naptanId")] public string NaptanId { get; set; }
[J("lon")] public long Lon { get; set; }
[J("stationNaptan")] public string StationNaptan { get; set; }
[J("status")] public bool Status { get; set; }
}
public partial class AffectedRoute
{
[J("id")] public string Id { get; set; }
[J("destinationName")] public string DestinationName { get; set; }
[J("$type")] public string Type { get; set; }
[J("direction")] public string Direction { get; set; }
[J("originationName")] public string OriginationName { get; set; }
[J("name")] public string Name { get; set; }
[J("routeSectionNaptanEntrySequence")] public List<RouteSectionNaptanEntrySequence> RouteSectionNaptanEntrySequence { get; set; }
}
public partial class RouteSectionNaptanEntrySequence
{
[J("ordinal")] public long Ordinal { get; set; }
[J("$type")] public string Type { get; set; }
[J("stopPoint")] public StopPoint StopPoint { get; set; }
}
public partial class StopPoint
{
[J("lat")] public long Lat { get; set; }
[J("commonName")] public string CommonName { get; set; }
[J("additionalProperties")] public List<object> AdditionalProperties { get; set; }
[J("$type")] public string Type { get; set; }
[J("children")] public List<object> Children { get; set; }
[J("icsCode")] public string IcsCode { get; set; }
[J("hubNaptanCode")] public string HubNaptanCode { get; set; }
[J("id")] public string Id { get; set; }
[J("lon")] public long Lon { get; set; }
[J("lineModeGroups")] public List<object> LineModeGroups { get; set; }
[J("lineGroup")] public List<object> LineGroup { get; set; }
[J("lines")] public List<object> Lines { get; set; }
[J("naptanId")] public string NaptanId { get; set; }
[J("stationNaptan")] public string StationNaptan { get; set; }
[J("modes")] public List<object> Modes { get; set; }
[J("placeType")] public string PlaceType { get; set; }
[J("status")] public bool Status { get; set; }
}
public partial class ValidityPeriod
{
[J("fromDate")] public string FromDate { get; set; }
[J("$type")] public string Type { get; set; }
[J("isNow")] public bool IsNow { get; set; }
[J("toDate")] public string ToDate { get; set; }
}
public partial class RouteSection
{
[J("direction")] public string Direction { get; set; }
[J("destination")] public string Destination { get; set; }
[J("$type")] public string Type { get; set; }
[J("destinationName")] public string DestinationName { get; set; }
[J("originationName")] public string OriginationName { get; set; }
[J("name")] public string Name { get; set; }
[J("originator")] public string Originator { get; set; }
[J("serviceType")] public string ServiceType { get; set; }
}
public partial class ServiceType
{
[J("name")] public string Name { get; set; }
[J("$type")] public string Type { get; set; }
[J("uri")] public string Uri { get; set; }
}
public partial class DataModel
{
public static ObservableCollection<DataModel> FromJson(string json) => JsonConvert.DeserializeObject<ObservableCollection<DataModel>>(json, Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this ObservableCollection<DataModel> self) => JsonConvert.SerializeObject(self, Converter.Settings);
}
public class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
};
}
}
And View2ViewModel.cs
is as follows:
using CrossPlatformTFL.Model;
using System.Collections.ObjectModel;
using System.Net.Http;
namespace CrossPlatformTFL.ViewModel
{
public class View2ViewModel
{
public ObservableCollection<DataModel> OpenData { get; set; } = new ObservableCollection<DataModel>();
public View2ViewModel()
{
using (HttpClient hc = new HttpClient())
{
//I would prefer to use `await` here but I cant figure it out either
var jsonString = hc.GetStringAsync("https://api.tfl.gov.uk/Line/Mode/tube%2Cdlr%2C%20overground/Status?detail=true").Result;
OpenData = DataModel.FromJson(jsonString);
}
}
}
}
My MainPage.xaml
is as following:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="CrossPlatformTFL.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:CrossPlatformTFL">
<ContentPage.Content>
<StackLayout>
<Label Text="Page One" />
<Label Text="Line Two" />
<Button Clicked="Button_Clicked" Text="Go to page two" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
And code behind for MainPage.xaml
:
using CrossPlatformTFL.View;
using System;
using Xamarin.Forms;
namespace CrossPlatformTFL
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
Navigation.PushAsync(new View2());
}
}
}
My View2.xaml
is:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="CrossPlatformTFL.View.View2"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<ContentPage.Content>
<StackLayout>
<Label Text="View2" />
<ListView ItemsSource="{Binding OpenData}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Detail="{Binding LineStatuses[0].StatusSeverityDescription}"
Text="{Binding Name}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
And Finally code behind for View2.xaml
using CrossPlatformTFL.ViewModel;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace CrossPlatformTFL.View
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class View2 : ContentPage
{
View2ViewModel vm;
public View2()
{
InitializeComponent();
vm = new View2ViewModel();
BindingContext = vm;
}
}
}
SO the plan was to Bind the data returned from the API to a list view and display them on View2.
As you can see above I cant use await
in the constructor for View2ViewModel.cs
thats my problem number one.
I would appreciate ideas how to get around that.
Second problem is also on View2ViewModel.cs
, specifically on
var jsonString = hc.GetStringAsync("https://api.tfl.gov.uk/Line/Mode/tube%2Cdlr%2C%20overground/Status?detail=true").Result;
On android the code breaks here and I dont have any information on that in the debugger:
Now surprisingly the code runs fine on UWP and displays api data on View2
:
Please help me to understand how can I await the API call and why its working on UWP but not on android?
You can download the debug the project HERE
P.S. My AndroidManifest.xml
is as follows:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto">
<uses-sdk android:minSdkVersion="15" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:label="CrossPlatformTFL.Android" android:icon="@drawable/icon"></application>
</manifest>
Edit 2:
applied try catch
to see the exception. Here is the exception message:
Upvotes: 0
Views: 1521
Reputation: 89169
public partial class View2 : ContentPage
{
View2ViewModel vm = null;
public View2()
{
InitializeComponent();
}
public override async void OnAppearing() {
if (vm == null) {
vm = new View2ViewModel();
await vm.FetchData();
BindingContext = vm;
}
}
}
public class View2ViewModel
{
public ObservableCollection<DataModel> OpenData { get; set; } = new ObservableCollection<DataModel>();
public async Task FetchData()
{
using (HttpClient hc = new HttpClient())
{
var jsonString = await hc.GetStringAsync("https://api.tfl.gov.uk/Line/Mode/tube%2Cdlr%2C%20overground/Status?detail=true");
OpenData = DataModel.FromJson(jsonString);
}
}
}
}
Upvotes: 2