Xamarin.Android - Making A Weather App

Introduction
 
In this article, I shall show you how to make a weather Android app using Open-Weather-Map API by geographic coordinates.
 
Prerequisites
  • Weather API Key
  • Newtonsoft.json Packages
  • AppCompat Android Library v7 
  • Picasso Images Caching Library
Step1
 
First, we need to open Weather Map API key. Go to https://openweathermap.org create an account and get the API key.
 
 
 
Step2
 
Open Visual Studio and go to New Project-> Templates-> Visual C#-> Android-> Blank app. Give it a name, like WeatherApp.
 
 
Step3
 
Next, go to Solution Explorer-> Project Name-> References. Then, right-click to "Manage NuGet Packages" and search for JSON. Install the Newtonsoft.Json Packages.
 
 
 
Step4
 
Next, we need to add a component that is required for layout. Open Solution Explorer and go to Components -> Get More Components. In this way, you can move on Xamarin Components Store, then search for AppCompat and click "Add to App".
 
 
 
 
Step5
 
Next, we need to add a more component that is required for caching images from web. Open Solution Explorer and go to Components -> Get More Components. In this way, you can move on Xamarin Components Store, then search for Picasso and click "Add to App".
 
 
Step6
 
Next, go to Solution Explorer-> Project Name and right-click. Select Add -> New Item-> Class. Give it a name, like Common.cs and write the following code with appropriate namespaces.
 
(Class Name: Common)
 
Note

Please must change API_KEY of your common class.   
  1. using System;  
  2. using System.Text;  
  3. namespace XamarinWeatherApp.Common {  
  4.     class Common {  
  5.         public static string API_KEY = "39a553a8c16c4d286e3acc2be7067c6e";  
  6.         public static string API_LINK = "https://api.openweathermap.org/data/2.5/weather";  
  7.         public static string APIRequest(string lat, string lng) {  
  8.             StringBuilder sb = new StringBuilder(API_LINK);  
  9.             sb.AppendFormat("?lat={0}&lon={1}&APPID={2}&units=metric", lat, lng, API_KEY);  
  10.             return sb.ToString();  
  11.         }  
  12.         public static DateTime UnixTimeStampToDateTime(double unixTimeStamp) {  
  13.             DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);  
  14.             dt = dt.AddSeconds(unixTimeStamp).ToLocalTime();  
  15.             return dt;  
  16.         }  
  17.         public static string GetImage(string icon) {  
  18.             return $ "http://openweathermap.org/img/w/{icon}.png";  
  19.         }  
  20.     }  
  21. }  
Step7

Similarly, create another class named as OpenWeatherMap.cs and write the following code with appropriate namespaces.
 
(File Name - OpenWeatherMap)
  1. using System.Collections.Generic;  
  2. namespace XamarinWeatherApp.Model {  
  3.     public class Coord {  
  4.         public double lon {  
  5.             get;  
  6.             set;  
  7.         }  
  8.         public double lat {  
  9.             get;  
  10.             set;  
  11.         }  
  12.     }  
  13.     public class Weather {  
  14.         public int id {  
  15.             get;  
  16.             set;  
  17.         }  
  18.         public string main {  
  19.             get;  
  20.             set;  
  21.         }  
  22.         public string description {  
  23.             get;  
  24.             set;  
  25.         }  
  26.         public string icon {  
  27.             get;  
  28.             set;  
  29.         }  
  30.     }  
  31.     public class Main {  
  32.         public double temp {  
  33.             get;  
  34.             set;  
  35.         }  
  36.         public double pressure {  
  37.             get;  
  38.             set;  
  39.         }  
  40.         public int humidity {  
  41.             get;  
  42.             set;  
  43.         }  
  44.         public double temp_min {  
  45.             get;  
  46.             set;  
  47.         }  
  48.         public double temp_max {  
  49.             get;  
  50.             set;  
  51.         }  
  52.         public double sea_level {  
  53.             get;  
  54.             set;  
  55.         }  
  56.         public double grnd_level {  
  57.             get;  
  58.             set;  
  59.         }  
  60.     }  
  61.     public class Wind {  
  62.         public double speed {  
  63.             get;  
  64.             set;  
  65.         }  
  66.         public double deg {  
  67.             get;  
  68.             set;  
  69.         }  
  70.     }  
  71.     public class Clouds {  
  72.         public int all {  
  73.             get;  
  74.             set;  
  75.         }  
  76.     }  
  77.     public class Sys {  
  78.         public double message {  
  79.             get;  
  80.             set;  
  81.         }  
  82.         public string country {  
  83.             get;  
  84.             set;  
  85.         }  
  86.         public int sunrise {  
  87.             get;  
  88.             set;  
  89.         }  
  90.         public int sunset {  
  91.             get;  
  92.             set;  
  93.         }  
  94.     }  
  95.     public class OpenWeatherMap {  
  96.         public Coord coord {  
  97.             get;  
  98.             set;  
  99.         }  
  100.         public List < Weather > weather {  
  101.             get;  
  102.             set;  
  103.         }  
  104.         public string @base {  
  105.             get;  
  106.             set;  
  107.         }  
  108.         public Main main {  
  109.             get;  
  110.             set;  
  111.         }  
  112.         public Wind wind {  
  113.             get;  
  114.             set;  
  115.         }  
  116.         public Clouds clouds {  
  117.             get;  
  118.             set;  
  119.         }  
  120.         public int dt {  
  121.             get;  
  122.             set;  
  123.         }  
  124.         public Sys sys {  
  125.             get;  
  126.             set;  
  127.         }  
  128.         public int id {  
  129.             get;  
  130.             set;  
  131.         }  
  132.         public string name {  
  133.             get;  
  134.             set;  
  135.         }  
  136.         public int cod {  
  137.             get;  
  138.             set;  
  139.         }  
  140.     }  
  141. }   
Step8 
 
Next, create another class named as Helper.cs and write the following code with appropriate namespaces.
 
(File Name - Helper)
  1. using Java.IO;  
  2. using Java.Net;  
  3. using System;  
  4. using System.Text;  
  5. namespace XamarinWeatherApp.Helper {  
  6.     public class Helper {  
  7.         static String stream = null;  
  8.         public Helper() {}  
  9.         public String GetHTTPData(String urlString) {  
  10.             try {  
  11.                 URL url = new URL(urlString);  
  12.                 using(var urlConnection = (HttpURLConnection) url.OpenConnection()) {  
  13.                     if (urlConnection.ResponseCode == HttpStatus.Ok) {  
  14.                         BufferedReader r = new BufferedReader(new InputStreamReader(urlConnection.InputStream));  
  15.                         StringBuilder sb = new StringBuilder();  
  16.                         String line;  
  17.                         while ((line = r.ReadLine()) != null) sb.Append(line);  
  18.                         stream = sb.ToString();  
  19.                         urlConnection.Disconnect();  
  20.                     }  
  21.                 }  
  22.             } catch (Exception ex) {  
  23.                 System.Diagnostics.Debug.WriteLine(ex.Message);  
  24.             }  
  25.             return stream;  
  26.         }  
  27.     }  
  28. }  
Step9
 
Now, open Solution Explorer-> Project Name-> Resources-> Layout-> Main.axml. Open this main layout file and add the following code.
 
(File Name: Main.axml)
 
(Folder Name: Layout)
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent">  
  3.     <TextView android:id="@+id/txtCity" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="40dp" android:text="" android:textSize="36sp" android:gravity="center" />  
  4.     <TextView android:id="@+id/txtLastUpdate" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="" android:textSize="16sp" android:gravity="center" />  
  5.     <ImageView android:id="@+id/imageView" android:layout_width="100dp" android:layout_height="100dp" android:layout_gravity="center" />  
  6.     <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txtDescription" android:text="" android:textSize="30sp" android:gravity="center" />  
  7.     <TextView android:id="@+id/txtHumidity" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="" android:textSize="30sp" android:gravity="center" />  
  8.     <TextView android:id="@+id/txtTime" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="" android:textSize="36sp" android:gravity="center" />  
  9.     <TextView android:id="@+id/txtCelsius" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="" android:textSize="80sp" android:gravity="center" />   
  10. </LinearLayout>  
Step10
 
Next, open Solution Explorer-> Project Name-> MainActivity. Open the main activity file and add the following code using appropriate namespaces.
 
Main Activity
  1. using Android.App;  
  2. using Android.Widget;  
  3. using Android.OS;  
  4. using Android.Locations;  
  5. using XamarinWeatherApp.Model;  
  6. using Android.Runtime;  
  7. using System;  
  8. using Square.Picasso;  
  9. using Newtonsoft.Json;  
  10. using Android.Content;  
  11. namespace XamarinWeatherApp {  
  12.     [Activity(Label = "WeatherApp", MainLauncher = true, Icon = "@drawable/icon", Theme = "@style/Theme.AppCompat.Light.NoActionBar")]  
  13.     public class MainActivity: Activity, ILocationListener {  
  14.         TextView txtCity, txtLastUpdate, txtDescription, txtHumidity, txtTime, txtCelsius;  
  15.         ImageView imgView;  
  16.         LocationManager locationManager;  
  17.         string provider;  
  18.         static double lat, lng;  
  19.         OpenWeatherMap openWeatherMap = new OpenWeatherMap();  
  20.         protected override void OnCreate(Bundle bundle) {  
  21.             base.OnCreate(bundle);  
  22.             // Set our view from the "main" layout resource  
  23.             SetContentView(Resource.Layout.Main);  
  24.             locationManager = (LocationManager) GetSystemService(Context.LocationService);  
  25.             provider = locationManager.GetBestProvider(new Criteria(), false);  
  26.             Location location = locationManager.GetLastKnownLocation(provider);  
  27.             if (location == null) System.Diagnostics.Debug.WriteLine("No Location");  
  28.         }  
  29.         protected override void OnResume() {  
  30.             base.OnResume();  
  31.             locationManager.RequestLocationUpdates(provider, 400, 1, this);  
  32.         }  
  33.         protected override void OnPause() {  
  34.             base.OnPause();  
  35.             locationManager.RemoveUpdates(this);  
  36.         }  
  37.         public void OnLocationChanged(Location location) {  
  38.             lat = Math.Round(location.Latitude, 4);  
  39.             lng = Math.Round(location.Longitude, 4);  
  40.             new GetWeather(this, openWeatherMap).Execute(Common.Common.APIRequest(lat.ToString(), lng.ToString()));  
  41.         }  
  42.         public void OnProviderDisabled(string provider) {}  
  43.         public void OnProviderEnabled(string provider) {}  
  44.         public void OnStatusChanged(string provider, [GeneratedEnum] Availability status, Bundle extras) {}  
  45.         private class GetWeather: AsyncTask < string, Java.Lang.Void, string > {  
  46.             private ProgressDialog pd = new ProgressDialog(Application.Context);  
  47.             private MainActivity activity;  
  48.             OpenWeatherMap openWeatherMap;  
  49.             public GetWeather(MainActivity activity, OpenWeatherMap openWeatherMap) {  
  50.                 this.activity = activity;  
  51.                 this.openWeatherMap = openWeatherMap;  
  52.             }  
  53.             protected override void OnPreExecute() {  
  54.                 base.OnPreExecute();  
  55.                 pd.Window.SetType(Android.Views.WindowManagerTypes.SystemAlert);  
  56.                 pd.SetTitle("Please wait....");  
  57.                 pd.Show();  
  58.             }  
  59.             protected override string RunInBackground(params string[] @params) {  
  60.                 string stream = null;  
  61.                 string urlString = @params[0];  
  62.                 Helper.Helper http = new Helper.Helper();  
  63.                 //urlString = Common.Common.APIRequest(lat.ToString(), lng.ToString());  
  64.                 stream = http.GetHTTPData(urlString);  
  65.                 return stream;  
  66.             }  
  67.             protected override void OnPostExecute(string result) {  
  68.                 base.OnPostExecute(result);  
  69.                 if (result.Contains("Error: Not City Found")) {  
  70.                     pd.Dismiss();  
  71.                     return;  
  72.                 }  
  73.                 openWeatherMap = JsonConvert.DeserializeObject < OpenWeatherMap > (result);  
  74.                 pd.Dismiss();  
  75.                 //Controls   
  76.                 activity.txtCity = activity.FindViewById < TextView > (Resource.Id.txtCity);  
  77.                 activity.txtLastUpdate = activity.FindViewById < TextView > (Resource.Id.txtLastUpdate);  
  78.                 activity.txtDescription = activity.FindViewById < TextView > (Resource.Id.txtDescription);  
  79.                 activity.txtHumidity = activity.FindViewById < TextView > (Resource.Id.txtHumidity);  
  80.                 activity.txtTime = activity.FindViewById < TextView > (Resource.Id.txtTime);  
  81.                 activity.txtCelsius = activity.FindViewById < TextView > (Resource.Id.txtCelsius);  
  82.                 activity.imgView = activity.FindViewById < ImageView > (Resource.Id.imageView);  
  83.                 //Add Data   
  84.                 activity.txtCity.Text = $ "{openWeatherMap.name},{openWeatherMap.sys.country}";  
  85.                 activity.txtLastUpdate.Text = $ "Last Updated: {DateTime.Now.ToString("  
  86.                 dd MMMM yyyy HH: mm ")}";  
  87.                 activity.txtDescription.Text = $ "{openWeatherMap.weather[0].description}";  
  88.                 activity.txtHumidity.Text = $ "Humidity: {openWeatherMap.main.humidity} %";  
  89.                 activity.txtTime.Text = $ "{Common.Common.UnixTimeStampToDateTime(openWeatherMap.sys.sunrise).ToString("  
  90.                 HH: mm ")}/{Common.Common.UnixTimeStampToDateTime(openWeatherMap.sys.sunset).ToString("  
  91.                 HH: mm ")}";  
  92.                 activity.txtCelsius.Text = $ "{openWeatherMap.main.temp} °C";  
  93.                 if (!string.IsNullOrEmpty(openWeatherMap.weather[0].icon)) {  
  94.                     Picasso.With(activity.ApplicationContext).Load(Common.Common.GetImage(openWeatherMap.weather[0].icon)).Into(activity.imgView);  
  95.                 }  
  96.             }  
  97.         }  
  98.     }  
  99. }   
Step11
 
We need some permissions from device. Let's open Solution Explorer and go to Properties-> AndroidManifest and add the following code inside application tags.
  1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  2. <uses-permission android:name="android.permission.INTERNET" />  
  3. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />  
  4. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />  
  5. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  
  6. <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />  
  7. <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />   
Finally, we have done our Weather app just rebuild and run the project. You will have the result like below.
 
Output