With the rising user base of mobile phones, app developers have an ever-increasing reach. Android has the largest share of apps among all the mobile OSes so it is quite evident that app developers would want to target this ecosystem. Earlier we covered a tutorial on how to build a simple Android app with an API. It’s time to add some complexity to it.
How about building a multi-screen Android app?
Choosing an API for a multi-screen Android App?
With the concerns around rising pollution levels in our cities, it is evident that people across the world would frequently search for air quality data. It is not easy to collect this data without the help of sophisticated pollution monitoring stations. However, with the integration of an API, it is possible to consume air quality data via an Android app.
The AirVisual API lets you query for air quality data based on a city. It is powered by IQAir, the world’s largest free real-time air quality information platform.
Follow the steps below to activate this API with your RapidAPI account.
1. Sign Up for RapidAPI Account
To begin using the AirVisual API, you’ll first need to sign up for a free RapidAPI developer account. With this account, you get a universal API Key to access all APIs hosted on RapidAPI.
RapidAPI is the world’s largest API marketplace, with over 10,000 APIs and a community of over 1,000,000 developers. Our goal is to help developers find and connect to APIs to help them build amazing apps.
2. Subscribe to AirVisual API
Once signed in, log on to your RapidAPI account and access the AirVisual API Console.
Now click on the “Pricing” tab and opt-in for the basic subscription that gives you 500 free API requests, per month.
3. Pull Air Quality Data For a City
Once subscribed, come back to the “Endpoints” tab on the API console. On the left panel, you can see a list of the endpoints supported by this API.
The API provides three ways to query Air quality data. You can get the data for a place, a city, or a weather station. As you can imagine, querying the data based on the city name is the most logical way. However, to do this, you must know the predefined city id associated with the city.
The “GET auto-complete” endpoint lets you search for a city to retrieve the id. After that, you can invoke the “GET cities/get-information” to retrieve the current air quality and weather data. To retrieve the historical air quality data, use the “GET cities/get-measurements” endpoint.
Let’s take the AirVisual API for a test drive and find the air quality index for Los Angeles. First, select the “GET auto-complete” endpoint and key in “Los Angeles” in the ‘query’ parameter for API requests to get a list of matching cities.
The API returns the matching city names, with the first entry representing the city of Los Angeles in the state of California in the US. The id of this city is “xwJyTC4tyag4svdTe”.
Now select the “GET cities/get-measurements” endpoint under the cities category in the endpoint list, and enter the id of Los Angeles in the ‘id’ parameter.
Triggering the API returns a response with two sets of measurements. The first one is the hourly measurement, and the second is daily measurement.
Expanding an hourly and daily measurement object gives specific values for air quality index values.
The ‘aqius’ gives the air quality index within a range of 0 to 500. This range is split into different concern levels to indicate the danger posed by air pollutants.
Courtesy, AQI basics
In case you are interested, the daily measurement data on API response also contains the density values for other polluting components of the air.
Displaying Air Quality Data on an Android App
Wouldn’t it be cool if you can display the air quality data on a mobile phone?
On a multi-screen Android app, you can do this by having the first screen display a dropdown of cities to choose from. Upon submit, the first screen navigates to the second screen that shows the air quality index for the chosen city.
From an Android app development point of view, these two screens are represented by two activities. So lets being out our programming mojos and build this Android app.
Before getting into coding the app, you need to take care of certain prerequisites to set up your development environment.
Prerequisites
For developing any Android app, your development computer must be installed with
- Android Studio: You can install the Android Studio version 3.0 or above. With this software, you get a complete suite of development tools along with an IDE to build your Android project.
- Android SDK: You must have the latest Android SDK (preferably Android 10.0) installed through the Android Studio. You can do this via the SDK manager. Check out the official guide on updating the IDE and SDK tools.
Assuming you have met the above prerequisites, follow the steps below to write and test your code within the Android Studio IDE.
Step 1: Setup a New Project on Android Studio
Launch the Android Studio and start a new project with an empty activity.
Click “Next” to enter the project name and choose other settings.
Make sure that you choose ‘Java’ for the Language, as this application will be built on Java.
Click “Finish” to exit the new project wizard and wait a few seconds until the Android Studio IDE comes alive with the project explorer displaying the main source code.
This is the MainActivity.java file. This activity handles the main screen of the app that displays a dropdown spinner to choose the city for which the air quality is displayed.
The air quality results for the chosen city gets displayed in a second screen represented by another activity. Let’s call it “DisplayResults”. You need to add it to the project.
To create a new activity within the project, right-click on the project explorer panel and select New > Activity > Basic Activity.
This will launch a dialog box for configuring the new activity. Type the activity name as “DisplayResults” and make sure that the other configurations are as shown.
Click “Finish”, and you should see a new file DisplayResults.java alongside the MainActivity.java.
With this, your project creation is now complete.
Step 2: Add App Resources for Displaying Images and Text on UI
Before getting into the details of UI layout and coding, you have to add a few accompanying resources for the app.
First, you need to define a few images to represent the air quality concern level icons. These icons will be selectively displayed on the DisplayResults activity as per the AQI index value.
Copy and paste these icon images into the app/res/drawable path within the project explorer. Ensure that you name the images as “good.png”, “moderate.png”, “unheanthy.png”, “unheanthy_sensitive.png”, “very_unhealty.png”, “hazardous.png” in the same order as displayed above.
Now, open the file strings.xml within the app/res/values path and replace the content with the following.
<resources> <string name="app_name">AirVisual</string> <string name="prompt_text">Select the city</string> <string name="submit_button">Get Air Quality</string> <string name="promptText">Select the city</string> <string name="submit">Submit</string> <string name="aquilabel">Air Quality Index</string> <string name="currentAqui">0</string> <string name="back">Back</string> <string name="city">City</string> <string name="current_air_quality">Current Air Quality</string> <string name="airquality">AirQuality</string> <string name="curentaqui">curentAqi</string> <string name="current_time">Current Time</string> <string name="horizontal_divider">Horizontal Divider</string> <string name="yesterday_value">Yesterday Value</string> <string name="yesterday_aqi_value">Yesterday Aqi Value</string> <string name="yesterday_date">Yesterday Date</string> <string name="daybefore_image">Daybefore Image</string> <string name="daybefore_aqi_value">Daybefore Aqi Value</string> <string name="daybefore_date">Daybefore Date</string> <string name="three_day_aqi_image">Three day Aqi Image</string> <string name="three_days_aqi_value">Three days Aqi Value</string> <string name="three_days_date">Three days date</string> <string name="current_aqi">Current Aqi</string> <string name="current_aqi_image">Current Aqi Image</string> <string name="appHeading">Air Quality Index</string> <string-array name="cities"> <item>London</item> <item>New York</item> <item>Tokyo</item> <item>Bangalore</item> </string-array> </resources>
Step 3: Add the UI Layout for Activities
Both the activities represented by MainActivity.java and DisplayResults.java represent UI components.
The layout for the UI components is defined under the app/res/layout path. Open the activity_main.xml file describing the MainActivity.
Replace this file with the following content.
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" tools:context=".MainActivity"> <TextView android:id="@+id/promptTextView" android:layout_width="178dp" android:layout_height="28dp" android:layout_marginTop="168dp" android:background="#FFFFFF" android:foregroundGravity="center_vertical|center_horizontal" android:gravity="center" android:text="@string/promptText" android:textColor="#000000" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Spinner android:id="@+id/spinner" android:layout_width="262dp" android:layout_height="42dp" android:layout_marginTop="224dp" android:background="#DCDCDC" android:foreground="@android:drawable/btn_dropdown" android:foregroundGravity="center_vertical|right" android:gravity="center" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.496" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:targetApi="m" /> <Button android:id="@+id/submit" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="312dp" android:paddingRight="10dp" android:paddingLeft="10dp" android:background="#2196F3" android:onClick="getMeasurement" android:text="@string/submit_button" app:layout_constraintCircleRadius="5dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/textView5" android:layout_width="263dp" android:layout_height="38dp" android:layout_marginTop="72dp" android:gravity="center" android:text="@string/appHeading" android:textColor="#000000" android:textSize="30sp" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
Save the file and you can see the layout UI mockup on MainActivity in the IDE.
Now open the activity_display_results.xml file representing the DisplayResults and replace the default code with the following XML definition.
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/displayResult" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".DisplayResults"> <TextView android:id="@+id/textView2" android:layout_width="203dp" android:layout_height="28dp" android:layout_marginTop="88dp" android:gravity="center" android:text="@string/aquilabel" android:textSize="24sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/resultCity" android:layout_width="123dp" android:layout_height="24dp" android:layout_marginTop="132dp" android:gravity="center" android:text="@string/city" android:textSize="18sp" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/currentAirQualityLabel" android:layout_width="157dp" android:layout_height="29dp" android:layout_marginTop="188dp" android:gravity="center" android:text="@string/current_air_quality" android:textSize="18sp" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:id="@+id/divider" android:layout_width="316dp" android:layout_height="3dp" android:layout_marginTop="372dp" android:background="#2196F3" android:contentDescription="@string/horizontal_divider" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.494" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@android:drawable/divider_horizontal_dark" /> <ImageView android:id="@+id/currentAqiImage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="56dp" android:layout_marginLeft="56dp" android:layout_marginTop="260dp" android:contentDescription="@string/current_aqi_image" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@drawable/good" /> <TextView android:id="@+id/currentAqiValue" android:layout_width="127dp" android:layout_height="27dp" android:layout_marginStart="160dp" android:layout_marginLeft="160dp" android:layout_marginTop="240dp" android:text="@string/airquality" android:textSize="18sp" android:textStyle="bold" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/currentAqi" android:layout_width="82dp" android:layout_height="26dp" android:layout_marginStart="212dp" android:layout_marginLeft="212dp" android:layout_marginTop="276dp" android:text="@string/current_aqi" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/currentTime" android:layout_width="85dp" android:layout_height="26dp" android:layout_marginStart="212dp" android:layout_marginLeft="212dp" android:layout_marginTop="304dp" android:text="@string/current_time" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:id="@+id/yesterdayAqiImage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="24dp" android:layout_marginLeft="24dp" android:layout_marginTop="448dp" android:contentDescription="@string/yesterday_value" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@drawable/good" /> <ImageView android:id="@+id/dayBeforeAqiImage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="448dp" android:contentDescription="@string/daybefore_image" app:layout_constraintEnd_toStartOf="@+id/threeDayAqiImage" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/yesterdayAqiImage" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@drawable/good" /> <ImageView android:id="@+id/threeDayAqiImage" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="448dp" android:layout_marginEnd="47dp" android:layout_marginRight="47dp" android:contentDescription="@string/three_day_aqi_image" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@drawable/good" /> <TextView android:id="@+id/yesterdayAqiValue" android:layout_width="79dp" android:layout_height="22dp" android:layout_marginStart="24dp" android:layout_marginLeft="24dp" android:layout_marginTop="544dp" android:gravity="center" android:text="@string/yesterday_aqi_value" android:textSize="18sp" android:textStyle="bold" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/dayBeforeAqiValue" android:layout_width="86dp" android:layout_height="21dp" android:layout_marginTop="540dp" android:gravity="center" android:text="@string/daybefore_aqi_value" android:textSize="18sp" android:textStyle="bold" app:layout_constraintEnd_toStartOf="@+id/threeDayAqiValue" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/yesterdayAqiValue" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/threeDayAqiValue" android:layout_width="78dp" android:layout_height="22dp" android:layout_marginTop="540dp" android:layout_marginEnd="44dp" android:layout_marginRight="44dp" android:gravity="center" android:text="@string/three_days_aqi_value" android:textSize="18sp" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/yesterdayDate" android:layout_width="82dp" android:layout_height="20dp" android:layout_marginStart="24dp" android:layout_marginLeft="24dp" android:layout_marginTop="576dp" android:gravity="center" android:text="@string/yesterday_date" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/dayBeforDate" android:layout_width="88dp" android:layout_height="20dp" android:layout_marginTop="576dp" android:gravity="center" android:text="@string/daybefore_date" app:layout_constraintEnd_toStartOf="@+id/threeDayDate" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/yesterdayDate" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/threeDayDate" android:layout_width="87dp" android:layout_height="21dp" android:layout_marginTop="580dp" android:layout_marginEnd="40dp" android:layout_marginRight="40dp" android:gravity="center" android:text="@string/three_days_date" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/textView" android:layout_width="39dp" android:layout_height="23dp" android:layout_marginStart="164dp" android:layout_marginLeft="164dp" android:layout_marginTop="276dp" android:text="AQI:" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/textView3" android:layout_width="44dp" android:layout_height="25dp" android:layout_marginStart="164dp" android:layout_marginLeft="164dp" android:layout_marginTop="304dp" android:text="Time:" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/textView4" android:layout_width="194dp" android:layout_height="24dp" android:layout_marginTop="398dp" android:text="Historical Air Quality" android:textSize="18sp" android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> </ScrollView>
The UI preview of DisplayResults looks like this.
Step 4: Write the Code for the Activities
With the UI layout defined, you are now ready to add the Java code to design this app’s behavior. Let’s do it one by one for both the activities.
First, open the MainActivity.java and replace the default content with the following code.
package com.example.airvisualapp; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.os.SystemClock; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Spinner; import org.json.JSONArray; import org.json.JSONObject; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Map; import java.util.*; public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener { String city = "London"; String apiKey = "<YOUR_RAPIDAPI_KEY>"; ProgressDialog p; HashMap<String,String> cityIdNameMap=new HashMap(); public MainActivity(){ // Initialize the city name to id hashmap cityIdNameMap.put("Bangalore","TsYYXDtYmgPZWggyt"); cityIdNameMap.put("London","7McFS9nFSf5TQmwva"); cityIdNameMap.put("Tokyo","mtEaKTNkstXxLfcw6"); cityIdNameMap.put("New York","gXTDkEBCX9BBKe5wc"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //create the spinner Spinner spinner = findViewById(R.id.spinner); ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,R.array.cities,android.R.layout.simple_spinner_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(adapter); spinner.setOnItemSelectedListener(this); } @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { this.city = parent.getItemAtPosition(position).toString(); } @Override public void onNothingSelected(AdapterView<?> parent) { } public String getCityId(String city){ return this.cityIdNameMap.get(city); } public void getMeasurement(View view){ String cityId; String query; try { DownloadTask task = new DownloadTask(); cityId = getCityId(this.city); query = "?id="+cityId; String urlWithQuery = "https://airvisual1.p.rapidapi.com/cities/get-measurements?id="+cityId; task.execute(urlWithQuery, this.city); } catch (Exception e) { e.printStackTrace(); } } public class DownloadTask extends AsyncTask<String,Void,String> { String selectedCity; String result = ""; @Override protected void onPreExecute() { super.onPreExecute(); p = new ProgressDialog(MainActivity.this); p.setMessage("Fetching Air Quality information ..."); p.setIndeterminate(false); p.setCancelable(false); p.show(); } @Override protected String doInBackground(String... params) { this.selectedCity = params[1]; URL apiURL; HttpURLConnection connection = null; try { apiURL = new URL(params[0]); connection = (HttpURLConnection) apiURL.openConnection(); // set headers for the request // set host name connection.setRequestProperty("x-rapidapi-host","airvisual1.p.rapidapi.com"); // set the rapid-api key connection.setRequestProperty("x-rapidapi-key", apiKey); connection.setRequestProperty("useQueryString", "true"); // set the request method - GET connection.setRequestMethod("GET"); InputStream in = connection.getInputStream(); InputStreamReader reader = new InputStreamReader(in); // read the response line by line BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in)); String temp, response = ""; while ((temp = bufferedReader.readLine()) != null) { response += temp; } return response; } catch (Exception e) { e.printStackTrace(); } // if not able to retrieve data return null return null; } String getAQIValue(String aqi){ // convert stri String value = "good"; // convert aqi to integer int intAqi = Integer.parseInt(aqi); if(0 <= intAqi && intAqi <= 50){ value = "Good"; } else if( 51 <= intAqi && intAqi <= 100 ) { value = "Moderate"; } else if ( 101 <= intAqi && intAqi <= 150 ){ value = "Unhealthy n for Sensitive"; } else if ( 151 <= intAqi && intAqi <=200 ){ value = "Unhealthy"; } else if ( 201 <= intAqi && intAqi <= 300){ value = "Very unhealthy"; } else if ( intAqi > 300) { value = "Hazardous"; } return value; } // format time from UTC to readable String formatTime(String utcDateTime){ String formattedTime=""; try{ SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.000Z'"); Date date = dateFormatter.parse(utcDateTime); dateFormatter.applyPattern("HH:mm"); formattedTime = (String) dateFormatter.format(date); } catch (Exception e){ e.printStackTrace(); } return formattedTime; } // format the date from utc to readable String formatDate(String utcDate){ String formattedDate=""; try { SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.000Z'"); Date date = dateFormatter.parse(utcDate); dateFormatter.applyPattern("MM/dd/yy"); formattedDate = (String) dateFormatter.format(date); } catch (Exception e){ e.printStackTrace(); } return formattedDate; } // construct the result view parameters from the data received JSONObject createResultViewParameters(JSONObject data) { JSONObject resultView = new JSONObject(); try { resultView.put("city",this.selectedCity); // get the current measurement from measurements object JSONArray measurements = (JSONArray) data.get("measurements"); JSONObject today = new JSONObject(); // extract todays aqi with time stamp and map aqi number to value today.put("ts", formatTime(measurements.getJSONObject(0).getString("ts"))); today.put("aqi",measurements.getJSONObject(0).getString("aqius")); today.put("value",getAQIValue(measurements.getJSONObject(0).getString("aqius"))); // add the json to resultview obeject resultView.put("today",today); // extract historical data for result display JSONArray dailyMeasurements = (JSONArray) data.get("measurements_daily"); // extract measurements for last 3 days if (dailyMeasurements.length() >= 4) { // values for yesterday JSONObject yesterday = new JSONObject().put("ts",formatDate(dailyMeasurements.getJSONObject(1).getString("ts"))); yesterday.put("aqius", dailyMeasurements.getJSONObject(1).getString("aqius")); yesterday.put("value", getAQIValue(dailyMeasurements.getJSONObject(1).getString("aqius"))); resultView.put("yesterday",yesterday); // values for day before JSONObject dayBefore = new JSONObject().put("ts", formatDate(dailyMeasurements.getJSONObject(2).getString("ts"))); dayBefore.put("aqius", dailyMeasurements.getJSONObject(2).getString("aqius")); dayBefore.put("value", getAQIValue(dailyMeasurements.getJSONObject(2).getString("aqius"))); resultView.put("daybefore",dayBefore); // values for 3 days before JSONObject threedays = new JSONObject().put("ts", formatDate(dailyMeasurements.getJSONObject(3).getString("ts"))); threedays.put("aqius", dailyMeasurements.getJSONObject(3).getString("aqius")); threedays.put("value", getAQIValue(dailyMeasurements.getJSONObject(3).getString("aqius"))); resultView.put("threedays",threedays); } } catch (Exception e){ e.printStackTrace(); } return resultView; } @Override protected void onPostExecute(String result) { super.onPostExecute(result); // stop the loading symbol p.hide(); p.dismiss(); try{ JSONObject resultJson = new JSONObject(result); String status = resultJson.getString("status"); if (!status.equals("success")){ //could not get the details so show error p.setMessage("Oops something went wrong please try again"); p.show(); SystemClock.sleep(5000); p.hide(); return; } // extract data JSONObject data = resultJson.getJSONObject("data"); // build result view parameters JSONObject resultJSON = new JSONObject(); resultJSON = createResultViewParameters(data); // navigate to result page //Intent resultPage = new Intent(getApplicationContext(), displayAQI.class); Intent resultPage = new Intent(getApplicationContext(),DisplayResults.class); resultPage.putExtra("result",resultJSON.toString()); startActivity(resultPage); finish(); } catch (Exception e){ System.out.println("Exception while parsing response"); e.printStackTrace(); } } } }
After replacing the code, update the placeholder <YOUR_RAPIDAPI_KEY> with your RapidAPI subscription key that you see on your API console.
The main trigger for this activity is the call to getMeasurement( ), which is initiated from the click event of the submit button.
This function invokes the AirVisual API’s “GET cities/get-measurement” endpoint to get the Air quality data for the selected city. We have created a predefined list of cities and have hard coded for the city Id as per the AirVisual API. This list includes London, New York, Tokyo, and Bangalore.
The API response is collected, and after formatting the data and time, the DisplayResults activity is triggered to display the data.
Open the DisplayResults.java and replace the default content with this code.
package com.example.airvisualapp; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import org.json.JSONObject; public class DisplayResults extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_display_results); ActionBar actionBar = this.getSupportActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); getSupportActionBar().setTitle("Back"); super.onCreate(savedInstanceState); try { // extract the parameters passed from MainActivity JSONObject result = new JSONObject(getIntent().getStringExtra("result")); setResultPage(result); } catch (Exception e) { e.printStackTrace(); } } @Override public boolean onSupportNavigateUp(){ Intent intent = new Intent(this,MainActivity.class); startActivity(intent); finish(); return true; } void setResultPage(JSONObject resultParams){ try { // set city TextView currentCity = (TextView) findViewById(R.id.resultCity); currentCity.setText(resultParams.getString("city")); // set today's parameters TextView currentAqi = (TextView) findViewById(R.id.currentAqi); currentAqi.setText(resultParams.getJSONObject("today").getString("aqi")); TextView currentAqiValue = (TextView) findViewById(R.id.currentAqiValue); currentAqiValue.setText(resultParams.getJSONObject("today").getString("value")); TextView currentTime = (TextView) findViewById(R.id.currentTime); currentTime.setText(resultParams.getJSONObject("today").getString("ts")); ImageView currentAqiImage = (ImageView) findViewById(R.id.currentAqiImage); currentAqiImage.setImageResource(getAqiImageId(resultParams.getJSONObject("today").getString("value"))); // set yesterdays's parameters TextView yesterdayAqiValue = (TextView) findViewById(R.id.yesterdayAqiValue); yesterdayAqiValue.setText(resultParams.getJSONObject("yesterday").getString("value")); TextView yesterdayDate = (TextView) findViewById(R.id.yesterdayDate); yesterdayDate.setText(resultParams.getJSONObject("yesterday").getString("ts")); ImageView yesterdayAqiImage = (ImageView) findViewById(R.id.yesterdayAqiImage); yesterdayAqiImage.setImageResource(getAqiImageId(resultParams.getJSONObject("yesterday").getString("value"))); // set day before yesterdays's parameters TextView daybeforeAqiValue = (TextView) findViewById(R.id.dayBeforeAqiValue); daybeforeAqiValue.setText(resultParams.getJSONObject("daybefore").getString("value")); TextView daybeforeDate = (TextView) findViewById(R.id.dayBeforDate); daybeforeDate.setText(resultParams.getJSONObject("daybefore").getString("ts")); ImageView daybeforeAqiImage = (ImageView) findViewById(R.id.dayBeforeAqiImage); daybeforeAqiImage.setImageResource(getAqiImageId(resultParams.getJSONObject("daybefore").getString("value"))); // set three days before yesterdays's parameters TextView threedayaeAqiValue = (TextView) findViewById(R.id.threeDayAqiValue); threedayaeAqiValue.setText(resultParams.getJSONObject("threedays").getString("value")); TextView threedaysDate = (TextView) findViewById(R.id.threeDayDate); threedaysDate.setText(resultParams.getJSONObject("threedays").getString("ts")); ImageView threedaysAqiImage = (ImageView) findViewById(R.id.threeDayAqiImage); threedaysAqiImage.setImageResource(getAqiImageId(resultParams.getJSONObject("threedays").getString("value"))); } catch (Exception e){ e.printStackTrace(); } } int getAqiImageId(String aqiValue){ int imageId = 0; if(aqiValue.equals("Good")){ imageId = R.drawable.good; } else if( aqiValue.equals("Moderate")) { imageId = R.drawable.moderate; } else if ( aqiValue.contains("Sensitive") ){ imageId = R.drawable.unhealthy_sensitive; } else if ( aqiValue.equals("Unhealthy") ){ imageId = R.drawable.unhealthy; } else if ( aqiValue.contains("Very")){ imageId = R.drawable.very_unhealthy; } else if ( aqiValue.equals("Hazardous")) { imageId = R.drawable.hazardous; } return imageId; } }
The main logic of the DisplayResults class is contained in setResultPage( ), which replaces the layout placeholders with the actual value obtained from API response.
Additionally, the getAqiImageId( ) returns the appropriate image to indicate the predefined concern level of air quality, as we saw earlier.
Step 5: Update Manifest Configuration
Finally, open the AndroidManifest.xml file under app/manifests path and replace the content with the following.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.airvisualapp"> <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.AppCompat"> <activity android:name=".DisplayResults" android:parentActivityName=".MainActivity"></activity> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
This file sets the main configuration for the app and also enables permission for internet access.
At this point, all the coding and configuration for your air quality Android app is complete.
Step 6: Run the App
To run this app, select from the menu, Run > Run’ app’, to launch the Android emulator with the app. First time execution of this step will take some time for building the app and launching the emulator.
Go ahead and select the city to check out the air quality levels.
If you want to test this app on a real Android phone, check out the official Android guide on building and running your app, and testing on a hardware device.
Conclusion
We hope you had a good experience building this app.
Working with APIs is very rewarding in terms of expediting your development effort. When it comes to pulling data from external systems, we have got you covered in many ways. For example, if you are looking at ways to enhance this app, please take a look at our weather API collection. Weather data can be added as additional information to augment the Air quality data results.
Stay tuned for more such app demos powered by RapidAPI.
How can we get air quality data for a city
With the help of RapidAPI, you can get the air quality information about cities. Log on to RapidAPI and search for AirVisual API. This API lets you search for daily and hourly air quality data for many cities from across the world.
How do I use an air quality API to retrieve pollution level in my city.
Log on to RapidAPI and search for AirVisual API. You will get a list of many API endpoints that provide a air quality data based on a location, city, or weather station.
How do I extract air quality parameters
To extract air quality parameters for a city, you can subscribe to the AirVisual API and lookup for the 'auto-complete' endpoint to search for the city id. Subsequently, using the id, you can get the air quality index and the density of pollutant components using the 'cities/get-measurements' endpoints This API is available as part of RapidAPI.
Leave a Reply