Browse through more Android tutorials. If you'd like to see a tutorial on any particular topic, do leave a comment in the wishlist page. We frequently post new tutorials along with app releases. You may subscribe to our newsletter to get all updates in your inbox.
Now you can get the latest Java source bundled with each app update. Install the app from Google Play and go to Settings > Extras.

«  Create Flappy Bird in Android Create a notepad/to-do list app  »

Create a currency converter application using Yahoo! API

DownloadDownload

Keywords: ConnectivityManager HttpGet XmlPullParser SAXParser SimpleCursorAdapter SQLiteDatabase ContentProvider SQLiteQueryBuilder BroadcastReceiver IntentService AChartEngine Search Dialog Animation TableLayout

Contents

5 « Prev Page


The MainActivity class is huge so we will implement it in parts. Here is the bare minimum code to display the currencies.







	public class MainActivity extends ListActivity {
		private SQLiteDatabase db;
		private Resources res;
		
		private Spinner baseSpinner;
		private EditText baseEdit;
		private ImageView processImg;

		private Animation animation;	

		@Override
		protected void onCreate(Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);
			requestWindowFeature(Window.FEATURE_NO_TITLE);
			setContentView(R.layout.main);

			db = ForexWiz.db;
			res = getResources();
			
			// TODO find views by id
		}	
		
		@Override
		protected void onResume() {
			super.onResume();
			final String baseCurrency = baseSpinner.getSelectedItem().toString();
			
			Cursor c = db.rawQuery("SELECT * FROM symbol AS s, quote AS q WHERE q.pair = ? || s.code AND s.isTracked = 1", 
									new String[]{baseCurrency});
			startManagingCursor(c);
			SimpleCursorAdapter adapter = new SimpleCursorAdapter(
					this, 
					R.layout.row, 
					c, 
					new String[]{"country", "name", "code"}, 
					new int[]{R.id.text1, R.id.text2, R.id.text3});
			
			adapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
				
				@Override
				public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
					TextView tv = (TextView) view;
					switch(view.getId()) {
					case R.id.text1:
						// get the country flag image
						int left = res.getIdentifier(cursor.getString(columnIndex), "drawable", "com.appsrox.forexwiz");
						tv.setCompoundDrawablesWithIntrinsicBounds(left, 0, 0, 0);
						tv.setCompoundDrawablePadding(10);
						return false;
						
					case R.id.text2:
					case R.id.text3:
						String currency = cursor.getString(cursor.getColumnIndex("code"));
						double price = cursor.getDouble(cursor.getColumnIndex("price"));
						double amt = Double.parseDouble(baseEdit.getText().toString());
						
						if (view.getId() == R.id.text2) {
							tv.setText(String.format("%f %s = %f %s", amt, baseCurrency, amt*price, currency));
						} else if (view.getId() == R.id.text3) {
							tv.setText(String.format("%f %s = %f %s", amt, currency, amt/price, baseCurrency));
						}
						return true;					
					}
					return false;
				}
			});
			setListAdapter(adapter);
		}	
	}
					
Now let's add logic to update the quotes by starting DataService that we implemented earlier. Add this piece of code in onCreate() method.
	Intent refresh = new Intent(getApplicationContext(), DataService.class);
	startService(refresh);
					
Additionally, create a receiver to listen to the status broadcast by DataService.
	private BroadcastReceiver statusReceiver = new  BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			if (intent != null && Constants.ACTION_REFRESH.equals(intent.getAction())) {
				switch (intent.getIntExtra(Constants.EXTRA_STATUS, 100)) {
				case Constants.STATUS_FAILED:
					Toast.makeText(context, getString(R.string.update_failed), Toast.LENGTH_SHORT).show();

				case Constants.STATUS_SUCCESS:
					runOnUiThread(new Runnable() {
		
						@Override
						public void run() {
							SimpleCursorAdapter adapter = (SimpleCursorAdapter) getListAdapter();
							adapter.notifyDataSetChanged();
							getListView().invalidateViews();
						}
					});					
					break;
				}
			}
		}
	};
					
As you can see we refresh the list view on successful update of quotes. We need to register the receiver in onResume() and unregister it in onPause() method.
	@Override
	protected void onResume() {
		super.onResume();
		
		registerReceiver(statusReceiver, new IntentFilter(Constants.ACTION_UPDATE));
		// ... 
	}
	
	@Override
	protected void onPause() {
		unregisterReceiver(statusReceiver);
		super.onPause();
	}	
					
We can show a little animation while the update is going on. For this we'll use Animation provided by Android. Create a XML file under res/anim directory with the following content.
	<?xml version="1.0" encoding="utf-8"?>
	<rotate xmlns:android="http://schemas.android.com/apk/res/android"
		android:fromDegrees="0"
		android:toDegrees="360"
		android:pivotX="50%"
		android:pivotY="50%"
		android:duration="2000"
		android:interpolator="@android:anim/linear_interpolator"
		android:repeatCount="infinite"
		android:repeatMode="restart">
	</rotate>
					
Next, load the animation in the onCreate() method.
	animation = AnimationUtils.loadAnimation(this, R.anim.progress);
					
Finally, start the animation before starting the DataService and stop it in the statusReceiver.
	processImg.startAnimation(animation);			
					
	processImg.clearAnimation();			
					
There are few other things left in the MainActivity like setting listeners on the Spinner and EditText so the list view gets refreshed when user changes the base currency or amount. Add the following code in the onCreate() method.
	baseSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

		@Override
		public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
			ForexWiz.setBaseCurrency(parent.getItemAtPosition(position).toString());
			getListView().invalidateViews();
		}

		@Override
		public void onNothingSelected(AdapterView<?> parent) {}
	});
	
	baseEdit.addTextChangedListener(new TextWatcher() {
		
		@Override
		public void onTextChanged(CharSequence s, int start, int before, int count) {}
		
		@Override
		public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
		
		@Override
		public void afterTextChanged(Editable s) {
			getListView().invalidateViews();
		}
	});
					
Also, onclick of a currency in the list view should launch a new screen to display details such as Ask, Bid, Change, etc. For this override onListItemClick() method in ListActivity.
	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		Intent intent = new Intent(this, InfoActivity.class);
		intent.putExtra(Constants.EXTRA_ID, id);
		startActivity(intent);
	}
					
Here is an useful tip for improving user experience of the app.

You can retain the scroll position of the ListView when the Activity is resumed or recreated by invoking setSelectionFromTop() on the ListView.

		int lastViewedPosition, topOffset;
		
		@Override
		protected void onSaveInstanceState(Bundle outState) {
			super.onSaveInstanceState(outState);
			outState.putInt("lastViewedPosition", lastViewedPosition);
			outState.putInt("topOffset", topOffset);
		}	

		@Override
		protected void onRestoreInstanceState(Bundle state) {
			super.onRestoreInstanceState(state);
			lastViewedPosition = state.getInt("lastViewedPosition");
			topOffset = state.getInt("topOffset");
		}	
		
		@Override
		protected void onResume() {
			super.onResume();
			
			// ...
			getListView().setSelectionFromTop(lastViewedPosition, topOffset);
		}

		@Override
		protected void onPause() {
			// ...
			lastViewedPosition = getListView().getFirstVisiblePosition();
			View v = getListView().getChildAt(0);
			topOffset = (v == null) ? 0 : v.getTop();
			
			super.onPause();
		}
					
We need to implement a onClick() method which we declared in the layout as the onClick callback for the buttons.
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.add_btn:
			onSearchRequested();
			break;
			
		case R.id.settings_btn:
			Intent settings = new Intent();
			settings.setClass(this, SettingsActivity.class);
			startActivity(settings);
			break;			
		}
	}
					
Last but not the least is to declare the activity in the manifest.
	<activity
		android:name=".MainActivity">
		<meta-data android:name="android.app.default_searchable"  
			android:value=".SearchableActivity" />
	</activity>
					

Did you notice search in onClick() method and in the manifest? We will next implement search in our application which will allow user to search a currency and add it to the list.
Share the love:  

Next Page » 5

App Gen
App Name:
Project Name:
Package:
Screens:
Splash
Login
Help
Main
List  Grid  Pager
Detail
Settings
Options:
Action Bar
Navigation Drawer
Dummy Data
Generate
Free Apps