Planning a vacation? Do it mobile REST Client style!

Written by DavidI on Posted in CLOUD

Planning a vacation? Like to know what the weather will be like at your chosen location? This article shows you how to build a mobile application using the REST Client Library components to choose a date, location and see current seven day weather forecast. You can start building the mobile vacation app using the File->New->Mobile Application to bring up the mobile application projects templates and choose the "Tabbed Application" template (click on the bitmaps in the article to see larger sized versions of all of this article's images). Since this app only need 3 tab items, you can delete one of the tabs.

The UI contains a TTabControl to contain three tabs for Weather, Browser and Settings. The app uses TGeocoder to get the latitude and longitude for an address. The app uses TWebBrowser to use Google Maps to display my vacation spot. I use TCalendarEdit to select the vacation date using the native date picker for iOS. Finally, the app uses the REST Client library components to access the WeatherBug weather forecast JSON api to display the next seven days of weather.

Here are the three TabItems in my mobile application:

The first thing the code does, using the form's OnCreate event, is initialize some variables, set up the Geocoder and load the WeatherBug API key from an INI file. I used the Project | Deployment menu to add the "weather.ini" file to my deployment and place it in the "StartUp\Documents" folder for iOS and in ".\assets\internal" for Android. [note: I place the INI file in the "c:\temp" folder on Windows - see the code for the OnCreate event handler]. Here is the INI file (minus my WeatherBug API key - you can get your own key by following the steps at http://developer.weatherbug.com/page):

weatherbug.ini:

[WeatherBug]
APIKey=xxxxx

Here is the Object Pascal code for the form's OnCreate event handler :

procedure TForm5.FormCreate(Sender: TObject);
var
   Ini: TIniFile;
begin
  // set up for Geocode
  FGeocoder := TGeocoder.Current.Create;
  FGeocoder.OnGeocode := OnGeocodeEvent;
  VacationTabControl.ActiveTab := WeatherTabItem;
  FoundLatitude := 0.0;
  FoundLongitude := 0.0;
  FoundAddrLatLong := false;
  RefreshButton.Visible := false;
  // read WeatherBug API Key from INI file
  {$IF DEFINED(IOS) or DEFINED(ANDROID) or DEFINED(MACOS)}
  Ini := TIniFile.Create(TPath.GetDocumentsPath + PathDelim + 'weather.ini');
  {$ELSE}
  Ini := TIniFile.Create('c:\temp\weather.ini');
  {$ENDIF}
  APIKeyString := Ini.ReadString('WeatherBug','APIKey','');
end;

The following bitmap shows the Project | Deployment entry for the "weather.ini" file showing it being deployed to the right folders on iOS (StartUp\Documents) and Android (.\assets\internal).

On the Settings TabItem, you can select your vacation date and address. When the address is changed, the OnChange event handler fires, stores the address in the TCivicAddress class and calls Geocode to get the new Latitude and Longitude. TGeocoder also has a GeocodeReverse method and OnGeocodeReverse event that takes latitude/longitude and returns TCivicAddress information. You can find more information about Geocoding and ReverseGeocoding on the Appmethod DocWiki. There is also an Object Pascal Mobile Tutorial: Using Location Sensors (iOS and Android) on the Appmethod DocWiki.

Here is the Object Pascal code for the AddressEditChange event.

procedure TForm5.AddressEditChange(Sender: TObject);
begin
  // Address changed - get Latitude/Longitude via GeoCoding
  RefreshButton.Visible := false;
  // use address to find Latitude and Longitude
  lAddress := TCivicAddress.Create;
  try
    lAddress.Address := AddressEdit.Text;
    FGeocoder.Geocode(lAddress);
  finally
    lAddress.Free;
  end;
end;

Geocode is called with the CivicAddress and when the geocoding completes, the OnGeocodeEvent fires. The parameter for the OnGeocodeEvent handler contains the coordinate array with the latitude and longitude. If the address is found and returns the coordinates, then I display them on the settings page and also call the Navigate method of the TWebBrowser to load a Google Map on the Browser TabItem.

Here is the Object Pascal code for the OnGeocodeEvent:

procedure TForm5.OnGeocodeEvent(const Coords: TArray);
begin
  if Length(Coords) > 0 then begin
    FoundLatitude := Coords[0].Latitude;
    FoundLongitude := Coords[0].Longitude;
    FoundAddrLatLong := true;
    LatLongLabel.Text :=
      Format('%3.5f/%3.5f',[Coords[0].Latitude, Coords[0].Longitude]);
    {$IF DEFINED(IOS) or DEFINED(ANDROID)}
    FormatSettings.DecimalSeparator := '.';
    WebBrowser1.Navigate(Format(LGoogleMapsURL, [FoundLatitude.ToString, FoundLongitude.ToString]));
    {$ENDIF}
    RefreshButton.Visible := true;
  end
  else begin
    FoundAddrLatLong := false;
    LatLongLabel.Text := 'Address not Found!'
  end;
end;

To finish the coding, my app has a TActionList component and I created an action, MyAction. The action executes when the RefreshButton is clicked. The RESTRequest is executed to call the WeatherBug weather REST GetForecast API and the RESTResponse gets the JSON result. The RESTRequestDataSetAdapter converts the returned JSON and populates the FDMemTable with the 7 days of weather forecast. The code fills in the WeatherListBox by iterating through the FDmemTable rows. Here are bitmaps of the REST Client components and their properties in the Object Inspector. I've circled in red the properties most used to process the API call and return the results to the FDMemTable.

Each ListBox item contains the high and low temperatures and the weather description for each day.

Here is the Object Pascal code for MyAction:

procedure TForm5.MyActionExecute(Sender: TObject);
var
  MyListBoxItem : TListBoxItem;
begin
  // days to vacation
  CountdownLabel.Text :=
    'Days to Vacation: '
    + IntToStr(DaysBetween(
        Now(),
        CalendarEdit1.Date)
      )
  ;

  if FoundAddrLatLong then begin

    // uses WeatherBug REST API
    // http://developer.weatherbug.com/docs/read/WeatherBug_Rest_XML_API
    // update RESTRequest Resource property
    // with latitude, longitude and API key
    RESTRequest1.Resource :=
      'REST/Direct/GetForecast.ashx?'
      + 'la='+FoundLatitude.ToString
      + '&'
      + 'lo='+FoundLongitude.ToString
      + '&ht=t&ht=i&ht=d&'
      + 'api_key='+APIKeyString
    ;

    // get weather temperatures
    RestRequest1.Execute;

    // Populate listbox with temperatures for next 7 days
    WeatherListBox.Items.Clear;
    WeatherListBox.BeginUpdate;
    FDMemTable1.First;
    while not FDMemTable1.Eof do begin
// TODO: get day and night icons for condition codes // For now just display strings MyListBoxItem := TListBoxItem.Create(WeatherListBox); MyListBoxItem.Text := copy(FDMemTable1.FieldByName('dayTitle').AsString,1,3) + ' Hi: ' + FDMemTable1.FieldByName('high').AsString + ' Lo: ' + FDMemTable1.FieldByName('low').AsString + ' ' + FDMemTable1.FieldByName('dayDesc').AsString ; MyListBoxItem.TextAlign := TTextAlign.taCenter; WeatherListBox.AddObject(MyListBoxItem); FDMemTable1.Next end; WeatherListBox.EndUpdate end end;

That's all of the code that I needed to write. For completeness, here is the form's declaration showing the components used and the privately declared variables and the OnGeoCodeEvent that are used throughout the application:

  TForm5 = class(TForm)
    ToolBar1: TToolBar;
    CountdownLabel: TLabel;
    Layout1: TLayout;
    WeatherListBox: TListBox;
    RefreshButton: TSpeedButton;
    ActionList1: TActionList;
    MyAction: TAction;
    RESTClient1: TRESTClient;
    RESTRequest1: TRESTRequest;
    RESTResponse1: TRESTResponse;
    BindingsList1: TBindingsList;
    RESTResponseDataSetAdapter1: TRESTResponseDataSetAdapter;
    BindSourceDB1: TBindSourceDB;
    LinkFillControlToField1: TLinkFillControlToField;
    ClientDataSet1: TClientDataSet;
    VacationTabControl: TTabControl;
    WeatherTabItem: TTabItem;
    SettingsTabItem: TTabItem;
    ListBox1: TListBox;
    AddressListBoxItem: TListBoxItem;
    LatLongListBoxItem: TListBoxItem;
    AddressEdit: TEdit;
    WebBrowser1: TWebBrowser;
    DateListBoxItem: TListBoxItem;
    CalendarEdit1: TCalendarEdit;
    LatLongLabel: TLabel;
    BrowserTabItem: TTabItem;
    procedure RefreshButtonClick(Sender: TObject);
    procedure MyActionExecute(Sender: TObject);
    procedure AddressEditChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    FoundAddrLatLong : boolean;  // if LatLong found using Address
    FoundLatitude : double;
    FoundLongitude : double;
    lAddress : TCivicAddress;
    APIKeyString : string;
    FGeocoder: TGeocoder;
    procedure OnGeocodeEvent(const Coords: TArray<TLocationCoord2D>);
  public
    { Public declarations }
  end;

Here are the live screens for the Appmethod app running on my iPhone 4S. The mobile app also runs on my Samsung Galaxy S4. The screens show: 1) Settings tab with the DatePicker, 2) Settings tab with the Address and latitude/longitude returned from the Geocoder, 3) Browser tab showing the Google Map and 4) Weather tab showing 7 days of weather forecast via the WeatherBug JSON API.

If you want to use other weather related APIs, there is a good blog post on ProgrammableWeb, "5 Weather APIs – From WeatherBug to Weather Channel", at http://blog.programmableweb.com/2009/04/15/5-weather-apis-from-weatherbug-to-weather-channel/. There are additional weather API sites at World Weather Online and ForeCast.io.

Click on this download zip file link to download the complete Mobile Vacation Countdown source project.

Tags: Appmethod iOS Android REST Client Library REST JSON Multi-Device



About
Gold User, Rank: 1, Points: 2466
David Intersimone (known to many as David I.) is a passionate and innovative software industry veteran-often referred to as a developer icon-who extols and educates the world on Embarcadero developer tools. He shares his visions as an active member of the industry speaking circuit and is tapped as an expert source by the media. He is a long-standing champion of architects, developers and database professionals and works to ensure that their needs are folded into Embarcadero's strategic product plans. David holds a bachelor's degree in computer science from California Polytechnic State University at San Luis Obispo, California.

Check out more tips and tricks in this development video: