Create a currency converter application using Yahoo! API
DownloadKeywords: ConnectivityManager HttpGet XmlPullParser SAXParser SimpleCursorAdapter SQLiteDatabase ContentProvider SQLiteQueryBuilder BroadcastReceiver IntentService AChartEngine Search Dialog Animation TableLayout
Contents- Overview
- Create a new Eclipse Android project
- Define the Data model
- The Android Manifest file
- The Application class
- Create a Preferences screen
- Implement the Init Task
- The Yahoo! Finance API
- The XmlPullParser
- The SAX Parser
- Calling RESTful service
- Implement the Data Service
- Create a splash screen
- Create the Main screen
- The Search Dialog
- Create the Info screen
- The AChartEngine library
6. Create a Preferences screen
Android provides an easy means to implement a preferences screen. Create a settings.xml file under res/xml directory using predefined preferences for ex. ListPreference, EditTextPreference, CheckBoxPreference, etc. Here is an excerpt from the XML file.<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > <PreferenceCategory android:title="General Settings"> <ListPreference android:key="base_currency" android:title="Base Currency" android:summary="USD" android:entries="@array/currency_names" android:entryValues="@array/currency_codes" android:defaultValue="USD" /> <EditTextPreference android:key="base_amt" android:title="Base Amount" android:summary="1.0" android:dialogTitle="Base Amount" android:inputType="numberDecimal" android:defaultValue="1.0" /> </PreferenceCategory> <PreferenceCategory android:title="Network Settings"> <CheckBoxPreference android:key="use_wifi" android:title="Use only Wi-Fi" android:summary="@string/wifi" android:defaultValue="false" /> </PreferenceCategory> </PreferenceScreen>ListPreference shows a list of choices which is specified through the android:entries attribute. Create an arrays.xml file under res/values directory if not already present. Declare each array using <string-array> tag as shown below.
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="currency_codes"> <item>USD</item> <item>EUR</item> <item>JPY</item> <item>GBP</item> <item>AUD</item> </string-array> <string-array name="currency_names"> <item>United States Dollar (USD)</item> <item>Euro (EUR)</item> <item>Japanese Yen (JPY)</item> <item>British Pound (GBP)</item> <item>Australian Dollar (AUD)</item> </string-array> </resources>
You can give any name to these files but they must be present under the appropriate directory (e.g. res/values or res/xml).
Next, create a new activity and make it extend PreferenceActivity. Additionally implement OnSharedPreferenceChangeListener interface so that when user changes a Preference value the summary gets updated.public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener { private SharedPreferences sp; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings); sp = getPreferenceScreen().getSharedPreferences(); } @Override protected void onResume(){ super.onResume(); sp.registerOnSharedPreferenceChangeListener(this); // TODO update preferences } @Override protected void onPause() { super.onPause(); sp.unregisterOnSharedPreferenceChangeListener(this); } @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { updatePreference(key); } }We create a generic method to update the summary of a preference when its value is changed. But you can handle individual cases by matching the Preference key which is passed as an argument.
private void updatePreference(String key){ Preference pref = findPreference(key); if (pref instanceof ListPreference) { ListPreference listPref = (ListPreference) pref; pref.setSummary(listPref.getEntry()); return; } if (pref instanceof EditTextPreference){ EditTextPreference editPref = (EditTextPreference) pref; editPref.setSummary(editPref.getText()); return; } if (pref instanceof CheckBoxPreference){ CheckBoxPreference checkPref = (CheckBoxPreference) pref; checkPref.setSummary(checkPref.isChecked() ? "True" : "False"); return; } }We've completed most of the preparatory work which is common for all our apps. Now let's start implementing the functionality.
7. Implement the Init Task
A currency converter app needs to be initialized with data (e.q. symbols, exchange rates, etc.) before it can be used for the first time. This involves populating the Symbol table with currency information and the Quote table with past exchange rates.We'll make use of AsyncTask to implement the init task. It executes in the background and on completion notifies the application to launch the Main screen. As you might have guessed we need a Splash screen for our app since the init task may take a while to complete.
Here is a basic outline of the InitTask class and we would implement the logic to populate the tables in subsequent sections.
public class InitTask extends AsyncTask<Void, Void, Integer> { private Context context; private SQLiteDatabase db; public InitTask(Context context) { super(); this.context = context; db = ForexWiz.db; } @Override protected Integer doInBackground(Void... params) { try { // TODO populate Symbol table // TODO populate Quote table } catch (SQLException e) { return Constants.STATUS_FAILED; } ForexWiz.setInitialized(); return Constants.STATUS_SUCCESS; } @Override protected void onPostExecute(Integer result) { Intent intent = new Intent(Constants.ACTION_INIT); intent.putExtra(Constants.EXTRA_STATUS, status); context.sendBroadcast(intent); } }We broadcast the status on completion of the task and set a boolean flag to true in the SharedPreferences so the task is not executed again if completed successfully. Add the following methods to ForexWiz.java
public static boolean isInitialized() { return sp.getBoolean(Constants.INITIALIZED, false); } public static void setInitialized() { sp.edit().putBoolean(Constants.INITIALIZED, true).commit(); }
8. The Yahoo! Finance API
Before we write code for populating the tables we need some Forex data. Fortunately, Yahoo! provides an API for developers which they themselves use in their Financial modules. You may want to check these resources to get familar with the API and also with Forex terminologies.- Yahoo data download
- Currency, Currencies & Forex Currency Trading - Yahoo! Finance
- Yahoo! Query Language - YDN
So now you got some idea about what sort of data you can get using the API and the format in which they are returned. For our purpose the following query returns sufficient data to initialize the Quote table.
http://finance.yahoo.com/webservice/v1/symbols/allcurrencies/quoteThis Http Get request returns a XML response with exchange rate against USD for World currencies. You can see it for yourself by putting the url in your browser address. Save the XML file in the project assets directory.
Here is an excerpt from the XML response.
<list version="1.0"> <meta> <type>resource-list</type> </meta> <resources start="0" count="164"> <resource classname="Quote"> <field name="name">USD/KRW</field> <field name="price">1129.234985</field> <field name="symbol">KRW=X</field> <field name="ts">1365062740</field> <field name="type">currency</field> <field name="volume">0</field> </resource> ... </resources> </list>We also need information such as currency name, country etc. to populate the Symbol table. We had to create our own XML file with the required data. You can get it from here and save it into the assets directory.
We'll next write code to read and parse these XML files and populate the DB tables.