Trainspotting Android app. This is my second android app from concept, design and finally to implementation. You can download this app from Google Play at Train Spotting.
In this post I discuss the details of the app threadbare. The app has all the usual goodies of android and uses the following features of Android
- Tab Layout
- List Layout with checkbox
- Options Menu with add, delete and deleteAll options
- Passing parameters between activities
- Handling the checkbox
- Using the assets folder
- Alert dialog
- Widgets like spinners, buttons, text fields etc
Actiity Flow
The picture below shows the flow between the different activities
Tab Layout
The app has 3 main tabs
- Favorites b) Locate Train c) Train At d) About.
Creating tabs is fairly straightforward
Create 3 tab xml files in the res/layout folder. The res/layout folder will also contain 3 xml files containing the icons that have to displayed when a tab is selected and when it not selected.
For the above 3 tabs the layout files are
- Favoritesa. Layout file – display.xml which is a list viewb. Icon file – favorites.xml
- Locatea. Layout file – locate_train.xml with spinners and buttonsb. Icon file – locate.xml3) About
a. Layout file – about.xml – Webview
b. Icon file – help.xml
For e.g.
display.xml has the following
<ListView xmlns:android=”http://schemas.android.com/apk/res/android”
android:id=”@android:id/list”
android:layout_width=”wrap_content”
android:layout_height=”match_parent” >
</ListView>
favorites.xml
?xml version=“1.0” encoding=“utf-8”?>
<selector xmlns:android=“http://schemas.android.com/apk/res/android”>
<!– When selected, use grey –>
<item android:drawable=“@drawable/star”
android:state_selected=“true” />
<!– When not selected, use white–>
<item android:drawable=“@drawable/star_1” />
</selector>
To create the above tab layout the following needs to added to the MainActivity to create the 3 tabs
// Create 3 tabs. Favorites, Locate, About
TabHost tabHost = getTabHost();
// Favorite trains tab
TabSpec favspec = tabHost.newTabSpec(“Favorites”);
// setting Title and Icon for the Tab
favspec.setIndicator(“Favorites”, getResources().getDrawable(R.drawable.star));
Intent favoritesIntent = new Intent(this, displayTrains.class);
favspec.setContent(favoritesIntent);
// Locate Train tab
TabSpec locatespec = tabHost.newTabSpec(“Locate”);
locatespec.setIndicator(“Locate”, getResources().getDrawable(R.drawable.binoculars));
Intent locateIntent = new Intent(this, locateTrain.class);
locatespec.setContent(locateIntent);
// About Tab
TabSpec aboutspec = tabHost.newTabSpec(“About”);
aboutspec.setIndicator(“About”, getResources().getDrawable(R.drawable.help));
Intent aboutIntent = new Intent(this, about.class);
aboutspec.setContent(aboutIntent);
// Add TabSpec to TabHost
tabHost.addTab(favspec);
tabHost.addTab(locatespec);
tabHost.addTab(aboutspec);
The app starts at the Main Activity and then immediately switches to the Favorites tab. This tab displays the current list of trains that the user has stored in the SQLiteDatabase.
Options Menu
The Favorites tab includes an Option Menu when the Options button on the device is pressed.
There are 3 options presented to the user
-
Add b) Delete c) deleteAll
To create an Options Menu add the options to the res/menu folder as options_menu.xml
The contents of res/menu/options_menu.xml is as follows
<?xml version=“1.0” encoding=“utf-8”?>
<menu xmlns:android=“http://schemas.android.com/apk/res/android”>
<item android:id=“@id/add”
android:icon=“@drawable/add”
android:title=“@string/add” />
<item android:id=“@id/delete”
android:icon=“@drawable/delete”
android:title=“@string/delete” />
<item android:id=“@id/deleteAll”
android:title=“@string/deleteAll”
android:icon=“@drawable/deleteall”/>
</menu>
This can be inflated in the Activity (displayTrains.java) as follows
publicboolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.options_menu, menu);
returntrue;
}
When a user selects an option the on the OptionItemSelectedMenu is invoked. There are currently 3 actions that can be selected from the OptionsMenu
a) Add b) Delete c) DeleteAll
Add option : When this option is selected the addTrain activity is started to take user input for the train no and train name
publicboolean onOptionsItemSelected(MenuItem item) {
Intent intent;
int count;
SqlOpenHelper helper = new SqlOpenHelper(this);
ArrayList<String> r = new ArrayList<String>();
final Context context = this;
switch (item.getItemId()) {
case R.id.add:
// Switch to the addTrain Activity
intent = new Intent(context, addTrain.class);
startActivity(intent);
returntrue;
The delete and the deleteAll option are also invoked in a similar fashion from the Option Menu
case R.id.delete:
…..
returntrue;
case R.id.deleteAll:
….
}
returntrue;
default:
returnsuper.onOptionsItemSelected(item);
}
}
Screen shot with the options menu
Passing parameters between activities
Sending parameters from one activity to another (locateTrain.java)
In the LocateTrain activity when the user selects the ‘train no’ and the ‘day” for which to locate the train the WebView has to be invoked with the selected values for the train no and day. This is done as as follows. In the calling activity locateTrain
Intent intent = new Intent(context, trainAt.class);
//Setup to pass parameters to new activity
// Pass the train & the day to the trainAt Activity
Bundle b = new Bundle();
b.putString(“train”, train_tokens[0]);
b.putString(“day”, dayValue);
intent.putExtras(b);
startActivity(intent);
The values are put in the bundle ‘b’ and the the parameters are passed with the call
intent.putExtras(b). The intent is finally started with the trainAt activity.
The trainAt activity receives the passed parameters are received as follows
Receiving parameters (trainAt.java)
// Receive the passed parameters
Bundle b = getIntent().getExtras();
int trainNo = Integer.parseInt(b.getString(“train”).toString());
String value = b.getString(“day”).toString();
// Invoke the web with passed parameters
String url = “http://www.spoturtrain.com/status.php?tno=” + trainNo + “&date=” +value;
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl(url);
Handling delete of selected items
To handle deletion of selected trains from the listview the delete() method is called. The code and the explanation is given below
SqlOpenHelper helper = new SqlOpenHelper(this);
ArrayList<String> r = new ArrayList<String>();
ListView lv = getListView();
SparseBooleanArray a = new SparseBooleanArray();
the lv.getCheckedItemPositions() returns a sparse array which has the checked items set to true.
// Create a sparse array of checked positions
a = lv.getCheckedItemPositions();
The list is iterated and the rows which are checked are determines as below
// Determine the positions which are checked
for(int pos=0;pos<lv.getCount(); pos++){
//Log.d(“val”,”pos:”+ pos + ” ” + a.get(pos));
if(a.get(pos)){
// If item is checked add it to the items ArrayList
items.add(pos);
}
}
//Convert the integer ArrayList to an Integer Array
Integer[] itemArray = new Integer[ items.size() ];
items.toArray( itemArray );
//Delete all selected items from SQLiteDatabase by passing in the itemArray
A train array is created with the selected rows and passed to deleteTrains()
helper.deleteTrains(itemArray);
// Clear the ArrayList
items.clear();
After deleting the selected rows the ListView is again re-populated with the new list.
//Re-populate the list
r = populateResults();
listAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_multiple_choice,r);
this.setListAdapter(listAdapter);
listAdapter.notifyDataSetChanged();
lv = getListView();
lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
Handling Cancel
As before the sparse array of checked items is obtained and each of them are set to false to uncheck them as below
// Get the checked positions in a Sparse Array
a = lv.getCheckedItemPositions();
for(int i=0;i<lv.getCount(); i++){
//Log.d(“val”,”i:”+ i + ” ” + a.get(i));
// Uncheck the checked positions
if(a.get(i)){
lv.setItemChecked(i, false);
}
}
// Clear the sparse Array. Clear the ArrayList
a.clear();
items.clear();
Using the assets folder
The About tab displays a Help file which is stored as a html in the
/assets folder.
To display the Web page, webview is used
publicclass about extends Activity {
publicvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.about);
// Add the trainspot.html in assets/
WebView webView = (WebView) findViewById(R.id.trainspot);
webView.loadUrl(“file:///android_asset/trainspot.html”);
}
}
Creating an alert dialog
An alert dialog is fairly straightforward
AlertDialog.Builder builder = new AlertDialog.Builder(context);
Set the title of the dialog and the message to be displayed as below
// Set title
builder.setTitle(“Confirm delete”);
a = lv.getCheckedItemPositions();
// Set the dialog message
builder.setMessage(“Do you want to delete these ” + a.size() + ” items?”);
Add either ‘Yes’/’No’ or ‘OK’/’Cancel’ buttons and handle the actions accordingly
// Add the Yes & No buttons
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
publicvoid onClick(DialogInterface dialog, int id) {
// User clicked Yes button
// Delete selected items
delete();
}
});
builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
publicvoid onClick(DialogInterface dialog, int id) {
// User No the dialog
// Uncheck the checked items
uncheck();
dialog.cancel();
}
});
// Create the AlertDialog
AlertDialog dialog = builder.create();
// show it
dialog.show();
This post gives all the finer details of this interesting app. Do install it and give it a try.
A sample output is shown below
You can clone the project from Github at Trainspotting or
The complete code of this app can be downloaded at trainspotting.zip
Happy train spotting!
You may also like
1. Unity (full) android app – With bells and whistles
2. The making of Dino Pong android game
One thought on “Train Spotting android app – Nuts and bolts”