Android Development Tutorial 5

android event listenerWelcome to part 5 of my Android Development Tutorial! In this tutorial, I completely finish the tip app that I have been making. If you want to learn about the Android event listener you are in the right place.

I will cover how to both get values from and change values in Android components.I also cover how to use changeListener, OnCheckedChangeListener, setOnCheckedChangeListener, OnItemSelectedListener, setOnItemSelectedListener, onItemSelected, setOnClickListener, and also how to turn a chronometer into a stop watch.

If you like videos like this, it helps to tell Google+ with a click here

Code From the Video

Here is a link to all of the code from my Android Tip Calculator. The code that changed in the tutorial is available below.

activity_crazy_tip_calc.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".CrazyTipCalc" >

    <requestFocus />

    <TextView
        android:id="@+id/billTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="14dp"
        android:layout_marginTop="14dp"
        android:text="@string/bill_text_view" />

    <!-- android:ems defines the width of the EditText box -->

    <EditText
        android:id="@+id/billEditText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_toRightOf="@+id/billTextView"
        android:ems="5"
        android:inputType="numberDecimal"
        android:text="@string/bill_edit_text" >

        <requestFocus />
    </EditText>

    <TextView
        android:id="@+id/tipTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/billTextView"
        android:layout_marginLeft="15dp"
        android:layout_toRightOf="@+id/billEditText"
        android:text="@string/tip_text_view" />

    <EditText
        android:id="@+id/tipEditText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/finalBillTextView"
        android:layout_marginLeft="18dp"
        android:layout_toRightOf="@+id/tipTextView"
        android:ems="4"
        android:inputType="numberDecimal"
        android:text="@string/tip_edit_text" />

    <TextView
        android:id="@+id/finalBillTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/finalBillEditText"
        android:layout_below="@+id/billEditText"
        android:layout_marginTop="14dp"
        android:text="@string/final_bill_text_view" />

    <EditText
        android:id="@+id/finalBillEditText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/tipEditText"
        android:layout_below="@+id/finalBillTextView"
        android:ems="5"
        android:inputType="numberDecimal"
        android:text="@string/final_bill_edit_text" />

    <TextView
        android:id="@+id/changeTipTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/finalBillTextView"
        android:layout_alignLeft="@+id/billTextView"
        android:text="@string/change_tip_text_view" />

    <!-- android:progress="15" defines the default for the SeekBar -->

    <SeekBar
        android:id="@+id/changeTipSeekBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/changeTipTextView"
        android:layout_alignTop="@+id/finalBillEditText"
        android:layout_marginTop="14dp"
        android:layout_toLeftOf="@+id/tipTextView"
        android:progress="15" />

    <!-- NEW STUFF -->

    <TextView
        android:id="@+id/IntroTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/changeTipSeekBar"
        android:layout_below="@+id/changeTipSeekBar"
        android:layout_marginTop="16dp"
        android:text="@string/intro_text_view" />

    <CheckBox
        android:id="@+id/friendlyCheckBox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignRight="@+id/IntroTextView"
        android:layout_below="@+id/IntroTextView"
        android:text="@string/intro_friendly_text_view" />

    <CheckBox
        android:id="@+id/specialsCheckBox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/friendlyCheckBox"
        android:layout_alignBottom="@+id/friendlyCheckBox"
        android:layout_alignRight="@+id/finalBillTextView"
        android:layout_marginRight="26dp"
        android:text="@string/intro_specials_text_view" />

    <CheckBox
        android:id="@+id/opinionCheckBox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/specialsCheckBox"
        android:layout_alignBottom="@+id/specialsCheckBox"
        android:layout_toRightOf="@+id/specialsCheckBox"
        android:text="@string/intro_opinion_text_view" />

<RadioGroup
    android:id="@+id/availableRadioGroup"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/IntroTextView"
    android:layout_alignRight="@+id/finalBillTextView"
    android:layout_below="@+id/availabilityTextView"
    android:layout_marginTop="15dp"
    android:orientation="horizontal" >

    <RadioButton
        android:id="@+id/availableBadRadio"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:checked="true"
        android:text="@string/available_bad_radiobutton" />

    <RadioButton
        android:id="@+id/availableOKRadio"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/available_ok_radiobutton" />

    <RadioButton
        android:id="@+id/availableGoodRadio"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/available_good_radiobutton" />
</RadioGroup>

<TextView
    android:id="@+id/availabilityTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/availableRadioGroup"
    android:layout_below="@+id/friendlyCheckBox"
    android:layout_marginTop="12dp"
    android:text="@string/available_text_view" />

<Spinner
    android:id="@+id/problemsSpinner"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/availableRadioGroup"
    android:layout_alignRight="@+id/opinionCheckBox"
    android:layout_below="@+id/availableRadioGroup"
    android:layout_marginTop="11dp"
    android:entries="@array/problem_solving" />

<TextView
    android:id="@+id/timeWaitingTextView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/problemsSpinner"
    android:layout_below="@+id/problemsSpinner"
    android:layout_marginTop="12dp"
    android:text="@string/time_waiting_text_view" />

<Chronometer
    android:id="@+id/timeWaitingChronometer"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignTop="@+id/timeWaitingTextView"
    android:layout_toRightOf="@+id/tipTextView"
    android:text="Chronometer" />

<Button
    android:id="@+id/startChronometerButton"
    style="?android:attr/buttonStyleSmall"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/timeWaitingTextView"
    android:layout_below="@+id/timeWaitingChronometer"
    android:layout_marginTop="16dp"
    android:text="@string/start_chronometer_button" />

<Button
    android:id="@+id/pauseChronometerButton"
    style="?android:attr/buttonStyleSmall"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignTop="@+id/startChronometerButton"
    android:layout_toRightOf="@+id/availabilityTextView"
    android:text="@string/pause_chronometer_button" />

<Button
    android:id="@+id/resetChronometerButton"
    style="?android:attr/buttonStyleSmall"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignTop="@+id/pauseChronometerButton"
    android:layout_toRightOf="@+id/changeTipSeekBar"
    android:text="@string/reset_chronometer_button" />

<!-- END OF NEW STUFF -->

</RelativeLayout>

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">CrazyTipCalc</string>
    <string name="action_settings">Settings</string>
    
    <string name="bill_text_view">Bill</string>
    <string name="bill_edit_text">0.0</string>
    
    <string name="tip_text_view">Tip</string>
    <string name="tip_edit_text">.15</string>
    
    <string name="final_bill_text_view">Final Bill</string>
    <string name="final_bill_edit_text">0.0</string>
    
    <string name="change_tip_text_view">Change Tip</string>
    
    <!-- END OF FIRST PART -->
    
    <string name="intro_text_view">Introduction</string>
    
    <string name="intro_friendly_text_view">Friendly</string>
    <string name="intro_specials_text_view">Specials</string>
    <string name="intro_opinion_text_view">Opinion</string>
    
    <string name="available_text_view">Availability</string>
    <string name="available_bad_radiobutton">Bad</string>
    <string name="available_ok_radiobutton">OK</string>
    <string name="available_good_radiobutton">Good</string>
    
    <string name="time_waiting_text_view">Time Waiting for Service</string>
    <string name="start_chronometer_button">Start</string>
    <string name="pause_chronometer_button">Pause</string>
    <string name="reset_chronometer_button">Reset</string>
    
    <!-- Spinner Options -->
    
	<string-array name="problem_solving">
	    <item>Problem Solving</item>
        <item>Bad</item>
        <item>OK</item>
        <item>Good</item>
    </string-array>

</resources>

CrazyTipCalc.java

package com.newthinktank.crazytipcalc;

import android.os.Bundle;
import android.os.SystemClock;
import android.app.Activity;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.Chronometer;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Spinner;
import android.widget.TextView;

public class CrazyTipCalc extends Activity {
	
	// Constants used when saving and restoring
	
	private static final String TOTAL_BILL = "TOTAL_BILL";
	private static final String CURRENT_TIP = "CURRENT_TIP";
	private static final String BILL_WITHOUT_TIP = "BILL_WITHOUT_TIP";
	
	private double billBeforeTip; // Users bill before tip
	private double tipAmount; // Tip amount
	private double finalBill; // Bill plus Tip
	
	EditText billBeforeTipET;
	EditText tipAmountET;
	EditText finalBillET;
	
	// NEW PART ---------------
	
	// Sum of all radio buttons and check boxes
	
	private int[] checklistValues = new int[12]; 
	
	// Declare CheckBoxes
	
	CheckBox friendlyCheckBox;
	CheckBox specialsCheckBox;
	CheckBox opinionCheckBox;
	
	// Declare RadioButtons
	
	RadioGroup availableRadioGroup;
	RadioButton availableBadRadio;
	RadioButton availableOKRadio;
	RadioButton availableGoodRadio;
	
	// Declare Spinner (Drop Down Box)
	
	Spinner problemsSpinner;
	
	// Declare Buttons
	
	Button startChronometerButton;
	Button pauseChronometerButton;
	Button resetChronometerButton;
	
	// Declare Chronometer
	
	Chronometer timeWaitingChronometer;
	
	// The number of seconds you spent 
	// waiting for the waitress
	
	long secondsYouWaited = 0;
	
	// TextView for the chronometer
	
	TextView timeWaitingTextView;
	
	
	// END OF NEW PART ---------------
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_crazy_tip_calc); // Inflate the GUI
		
		// Check if app just started, or if it is being restored
		
		if(savedInstanceState == null){
			
			// Just started
			
			billBeforeTip = 0.0;
			tipAmount = .15; 
			finalBill = 0.0; 
			
		} else {
			
			// App is being restored
			
			billBeforeTip = savedInstanceState.getDouble(BILL_WITHOUT_TIP);
			tipAmount = savedInstanceState.getDouble(CURRENT_TIP); 
			finalBill = savedInstanceState.getDouble(TOTAL_BILL); 
			
		}
		
		// Initialize the EditTexts
		
		billBeforeTipET = (EditText) findViewById(R.id.billEditText); // Users bill before tip
		tipAmountET = (EditText) findViewById(R.id.tipEditText); // Tip amount
		finalBillET = (EditText) findViewById(R.id.finalBillEditText); // Bill plus tip
		
		// Initialize the SeekBar and add a ChangeListener
		
		tipSeekBar = (SeekBar) findViewById(R.id.changeTipSeekBar);
		
		tipSeekBar.setOnSeekBarChangeListener(tipSeekBarListener);
		
		// ---------------------------
		
		// Add change listener for when the bill before tip is changed
		
		billBeforeTipET.addTextChangedListener(billBeforeTipListener);
		
		// NEW PART ---------------
		
		// Initialize CheckBoxs
		
		friendlyCheckBox = (CheckBox) findViewById(R.id.friendlyCheckBox);
		specialsCheckBox = (CheckBox) findViewById(R.id.specialsCheckBox);
		opinionCheckBox = (CheckBox) findViewById(R.id.opinionCheckBox);
		
		setUpIntroCheckBoxes(); // Add change listeners to check boxes
		
		// Initialize RadioButtons
		
		availableBadRadio = (RadioButton) findViewById(R.id.availableBadRadio);
		availableOKRadio = (RadioButton) findViewById(R.id.availableOKRadio);
		availableGoodRadio = (RadioButton) findViewById(R.id.availableGoodRadio);
		
		// Initialize RadioGroups
		
		availableRadioGroup = (RadioGroup) findViewById(R.id.availableRadioGroup);
		
		// Add ChangeListener To Radio buttons
		
		addChangeListenerToRadios();
		
		// Initialize the Spinner
		
		problemsSpinner = (Spinner) findViewById(R.id.problemsSpinner);
		
		problemsSpinner.setPrompt("Problem Solving");
		
		// Add ItemSelectedListener To Spinner
		
		addItemSelectedListenerToSpinner();
		
		// Initialize Buttons
		
		startChronometerButton = (Button) findViewById(R.id.startChronometerButton);
		pauseChronometerButton = (Button) findViewById(R.id.pauseChronometerButton);
		resetChronometerButton = (Button) findViewById(R.id.resetChronometerButton);
		
		// Add setOnClickListeners for buttons
		
		setButtonOnClickListeners();
		
		// Initialize Chronometer
		
		timeWaitingChronometer = (Chronometer) findViewById(R.id.timeWaitingChronometer);
		
		// TextView for Chronometer
		
		timeWaitingTextView = (TextView) findViewById(R.id.timeWaitingTextView);
		
		// END OF NEW PART ---------------
	}
	
	// Called when the bill before tip amount is changed
	
	private TextWatcher billBeforeTipListener = new TextWatcher(){

		@Override
		public void afterTextChanged(Editable arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
				int arg3) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onTextChanged(CharSequence arg0, int arg1, int arg2,
				int arg3) {
			
			try{
				
				// Change the billBeforeTip to the new input
				
				billBeforeTip = Double.parseDouble(arg0.toString());
				
			}
			
			catch(NumberFormatException e){
				
				billBeforeTip = 0.0;
				
			}
			
			updateTipAndFinalBill();
			
		}
		
	};
	
	// Update the tip amount and add tip to bill to
	// find the final bill amount
	
	private void updateTipAndFinalBill(){
		
		// Get tip amount
		
		double tipAmount = Double.parseDouble(tipAmountET.getText().toString());
		
		// The bill before tip amount was set in billBeforeTipListener
		
		// Get the bill plus the tip
		
		double finalBill = billBeforeTip + (billBeforeTip * tipAmount);
		
		// Set the total bill amount including the tip
		// Convert into a 2 decimal place String
		
		finalBillET.setText(String.format("%.02f", finalBill));
		
	}
	
	// Called when a device changes in some way. For example,
	// when a keyboard is popped out, or when the device is 
	// rotated. Used to save state information that you'd like
	// to be made available.
	
	@Override
	protected void onSaveInstanceState(Bundle outState){
		
		super.onSaveInstanceState(outState);
		
		outState.putDouble(TOTAL_BILL, finalBill);
		outState.putDouble(CURRENT_TIP, tipAmount);
		outState.putDouble(BILL_WITHOUT_TIP, billBeforeTip);
		
	}
	
	// SeekBar used to make a custom tip
	
	private SeekBar tipSeekBar;
	
	private OnSeekBarChangeListener tipSeekBarListener = new OnSeekBarChangeListener(){

		@Override
		public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
			
			// Get the value set on the SeekBar
			
			tipAmount = (tipSeekBar.getProgress()) * .01;
			
			// Set tipAmountET with the value from the SeekBar
			
			tipAmountET.setText(String.format("%.02f", tipAmount));
			
			// Update all the other EditTexts
			
			updateTipAndFinalBill();
			
		}

		@Override
		public void onStartTrackingTouch(SeekBar arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void onStopTrackingTouch(SeekBar arg0) {
			// TODO Auto-generated method stub
			
		}
		
	};
	
	// ---- NEW STUFF ----------
	
	private void setUpIntroCheckBoxes(){
		
		// Add ChangeListener to the friendlyCheckBox
		
		friendlyCheckBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener(){

			@Override
			public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
						
				// Use java ternary operator to set the right values for
				// each item on the waitress check box checklist
						
				checklistValues[0] = (friendlyCheckBox.isChecked())?4:0;
				
				// Calculate tip using the waitress checklist options
				
				setTipFromWaitressChecklist(); 
						
				// Update all the other EditTexts
						
				updateTipAndFinalBill();
						
			}
					
		});
		
		// Add ChangeListener to the specialsCheckBox
		
		specialsCheckBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener(){

			@Override
			public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
						
				// Use java ternary operator to set the right values for
				// each item on the waitress check box checklist
						
				checklistValues[1] = (specialsCheckBox.isChecked())?1:0;
				
				// Calculate tip using the waitress checklist options
				
				setTipFromWaitressChecklist(); 
						
				// Update all the other EditTexts
						
				updateTipAndFinalBill();
						
			}
					
		});		
		
		// Add ChangeListener to the opinionCheckBox
		
		opinionCheckBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener(){

			@Override
			public void onCheckedChanged(CompoundButton arg0, boolean arg1) {
						
				// Use java ternary operator to set the right values for
				// each item on the waitress check box checklist
						
				checklistValues[2] = (opinionCheckBox.isChecked())?2:0;
				
				// Calculate tip using the waitress checklist options
				
				setTipFromWaitressChecklist(); 
						
				// Update all the other EditTexts
						
				updateTipAndFinalBill();
						
			}
					
		});				
		
	}
	
	// Calculate tip using the waitress checklist options
	
	private void setTipFromWaitressChecklist(){
		
		int checklistTotal = 0;
		
		// Cycle through all the checklist values to calculate
		// a total amount based on waitress performance
		
		for(int item : checklistValues){
			
			checklistTotal += item;
			
		}
		
		// Set tipAmountET 
		
		tipAmountET.setText(String.format("%.02f", checklistTotal * .01));
		
	}
	
	private void addChangeListenerToRadios(){
		
		// Setting the listeners on the RadioGroups and handling them
		// in the same location
		
		availableRadioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() 
	    {
			// checkedId is the RadioButton selected
	        public void onCheckedChanged(RadioGroup group, int checkedId) {
	        	
	        	// Use java ternary operator to set the right values for
	    		// each item on the waitress radiobutton checklist
	        	
	        	checklistValues[3] = (availableBadRadio.isChecked())?-1:0;
	        	checklistValues[4] = (availableOKRadio.isChecked())?2:0;
	        	checklistValues[5] = (availableGoodRadio.isChecked())?4:0;
	        	
	        	// Calculate tip using the waitress checklist options
				
				setTipFromWaitressChecklist(); 
						
				// Update all the other EditTexts
						
				updateTipAndFinalBill();
	        	
	        }
	    });
		
	}
	
	// Adds Spinner ItemSelectedListener
	
	private void addItemSelectedListenerToSpinner(){
		
		problemsSpinner.setOnItemSelectedListener(new OnItemSelectedListener(){

			@Override
			public void onItemSelected(AdapterView<?> arg0, View arg1,
					int arg2, long arg3) {
				
				checklistValues[6] = (String.valueOf(problemsSpinner.getSelectedItem()).equals("Bad"))?-1:0;
				checklistValues[7] = (String.valueOf(problemsSpinner.getSelectedItem()).equals("OK"))?3:0;
				checklistValues[8] = (String.valueOf(problemsSpinner.getSelectedItem()).equals("Good"))?6:0;
				
				// Calculate tip using the waitress checklist options
				
				setTipFromWaitressChecklist(); 
						
				// Update all the other EditTexts
						
				updateTipAndFinalBill();
				
			}

			@Override
			public void onNothingSelected(AdapterView<?> arg0) {
				// TODO Auto-generated method stub
				
			}
			
		});
		
	}
	
	// Adds ClickListeners for buttons so they can control
	// the chronometer
	
	private void setButtonOnClickListeners(){
		
		startChronometerButton.setOnClickListener(new OnClickListener(){

			@Override
			public void onClick(View arg0) {
				
				// Holds the number of milliseconds paused
				
				int stoppedMilliseconds = 0;
				
				// Get time from the chronometer
				
			    String chronoText = timeWaitingChronometer.getText().toString();
			    String array[] = chronoText.split(":");
			    if (array.length == 2) {
			    	
			    	// Find the seconds
			    	
			      stoppedMilliseconds = Integer.parseInt(array[0]) * 60 * 1000
			            + Integer.parseInt(array[1]) * 1000;
			    } else if (array.length == 3) {
			    	
			    	// Find the minutes
			    	
			      stoppedMilliseconds = Integer.parseInt(array[0]) * 60 * 60 * 1000 
			            + Integer.parseInt(array[1]) * 60 * 1000
			            + Integer.parseInt(array[2]) * 1000;
			    }
			    
			    // Amount of time elapsed since the start button was
			    // pressed, minus the time paused

			    timeWaitingChronometer.setBase(SystemClock.elapsedRealtime() - stoppedMilliseconds);
			    
			    // Set the number of seconds you have waited
			    // This would be set for minutes in the real world
			    // obviously. That can be found in array[2]
			    
			    secondsYouWaited = Long.parseLong(array[1]);
			    
			    updateTipBasedOnTimeWaited(secondsYouWaited);
			    
			    // Start the chronometer
			    
			    timeWaitingChronometer.start();
				
			}
			
			
		});
		
		pauseChronometerButton.setOnClickListener(new OnClickListener(){

			@Override
			public void onClick(View arg0) {
				
				timeWaitingChronometer.stop();
				
			}
			
			
		});
		
		resetChronometerButton.setOnClickListener(new OnClickListener(){

			@Override
			public void onClick(View arg0) {
				
				timeWaitingChronometer.setBase(SystemClock.elapsedRealtime());
				
				// Reset milliseconds waited back to 0
				
				secondsYouWaited = 0;
				
			}
			
			
		});
		
	}
	
	private void updateTipBasedOnTimeWaited(long secondsYouWaited){
		
		// If you spent less then 10 seconds then add 2 to the tip
		// if you spent more then 10 seconds subtract 2
		
		checklistValues[9] = (secondsYouWaited > 10)?-2:2;
		
		// Calculate tip using the waitress checklist options
		
		setTipFromWaitressChecklist(); 
				
		// Update all the other EditTexts
				
		updateTipAndFinalBill();
		
	}
	
	// ---- END OF NEW STUFF ----------

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.crazy_tip_calc, menu);
		return true;
	}

}

82 Responses to “Android Development Tutorial 5”

  1. punit says:

    nice tutorial darek, i have a question not related to android.
    just wanted to know how to create images, i was just thinking to make a pretty website, but i don’t know how do i create kool images or collection of images which i will need to make the website, lots of videos i watched on youtube but they are taking “existing image” and making that beautiful, but i want to make images, not to take existing.

  2. punit says:

    for ex: a cool background image for website.

  3. Alberto Noys says:

    Hi, Derek!

    This is my first time seriously diving into coding so forgive me if these are problems that are easily solved, I’m trying hard to wrap my head around all of this.

    I get two errors when creating addChangeListenerToRadios, even if I copy your code in the .java.

    One says there’s still unimplemented methods for OnCheckChangeListener: http://i.imgur.com/VBdECY9.png

    That’s because your automatically implemented methods are different from mine, when I implement onCheckedChanged the attributes are not RadioGroup and an integer, instead it’s CompoundButton buttonView and boolean isChecked.
    That’s one.

    And the other one is this one: http://i.imgur.com/2io92yd.png and in this I got no clue about what is happening.

    Any help is greatly appreciated. And thank you so much for doing this! I can’t even begin express my gratitude.

    • Derek Banas says:

      I’m just wondering if you are closing the method or not? Make sure you close it like this });

      You can see what I’m referring to on line 426 on this page

      If you are still getting an error, try loading my exact code in and run it to make sure Eclipse is properly set up. I hope that helps

      • Alberto Noys says:

        It is closed, yes. Take a look: http://i.imgur.com/iIGZjvn.png

        And this is the error: http://i.imgur.com/kpV4kad.png

        I’ve tried copying your exact code for that function (I think it’s called a function, forgive me if I’m wrong) and it gives me the errors that I showed you in the last comment.

        What is weird is that if I replace my whole CrazyTipCalc.java code with yours, the same function that was giving me errors before works properly and without errors.

      • Alberto Noys says:

        Ok. After researching a little I’ve fixed it.

        Specifying “(new RadioGroup.OnCheckedChangeListener()” instead of just “(OnCheckedChangeListener()” did it.
        Sorry for the inconvenience!

        • Derek Banas says:

          I’m happy that you fixed it. Sorry that I couldn’t get to you quicker

        • Jeff says:

          I too had this problem. Thanks for the fix, I thought it was odd that the checkboxes needed it declared (CheckBox.OnCheckedChangeListener) but the radio group did not. It seems Eclipse/Android defaults to CompoundButton.OnCheckedChangeListener if you don’t specify in out instances.

          Thanks again Derek for the great tutorials.

        • Esat Bektaş says:

          thanks for solution it solves my problem too

  4. Maggi says:

    Hi Derek,

    I am just wondering how do you know these many things. Please share the secret :)

    Its hard , in fact pretty much difficult i guess, but how have you mastered all these technologies…

    How one has to target to master all these technologies or target to become 10% of Derek ???

    Please reply.

    • Derek Banas says:

      I’m not all that amazing. I’m just pretty good at a small number of subjects. I grew up idolizing Sherlock Holmes. One of the quotes that stuck with me when I was little was this.

      I consider that a man’s brain originally is like a little empty attic, and you have to stock it with such furniture as you choose. A fool takes in all the lumber of every sort that he comes across, so that the knowledge which might be useful to him gets crowded out, or at best is jumbled up with a lot of other things, so that he has a difficulty in laying his hands on it. Now the skillful workman is very careful indeed as to what he takes into his brain-attic. He will have nothing but the tools which may help him in doing his work, but of these he has a large assortment, and all in the most perfect order. It is a mistake to think that little room has elastic walls and can distend to any extent. Depend uon it – there comes a time when for every addition of knowledge you forget something that you knew before. It is of the highest importance, therefore, not to have useless facts elbowing out the useful ones.

      I always worked to never learn anything that wasn’t perfectly useful for my work. I’m not saying that is a way to live, but it is the way I am. Most people are astounded by the little I know about pop culture. I haven’t listened to music in decades. I only ever watch 2 tv shows a week. I’m rather odd actually :)

      So, that is a bit about my strange brain. Always feel free to ask questions. I’ll do my best to help

      Derek

  5. Phil says:

    Hey Derek…Waiting for part 6 of the Android Tutorials soooooo much. When is it coming. I really enjoy your tutorials so much. When am done i will look for you just to say thank you and get to know the face of this genius guy. Thanks

  6. Lakhs says:

    Hi… Thanks For the Quality and Clarity of your Lessons, i can only imagine the time and effort they take to construct…

    For that we are all truly grateful.

    I do have a question i would like to ask:

    How do i test this app on my real android mobile?

    Thanks again

    • Derek Banas says:

      Thank you very much :) I’m very happy that more people have been finding and enjoying my videos recently. As per running the apps on your device, just connect it with a USB. Click Run Configurations and select your apps name in Project. Select Launch and select your MainActivity. Click the tab labeled Target and select the radio button named Launch on all compatible devices/AVD’s. That will load the app on your mobile. I hope that helps

      • Lakhs says:

        Wow that was cool thanks…

        (don’t reply i know your busy)

      • Lakhs says:

        I do have a request for the next App…

        When testing the CrazyTipCalc App on Mobile device it didnt look right when i turned it horizontally…

        maybe you could correct it on the next App we do.

        Cheers

        • Derek Banas says:

          These apps aren’t meant to be 100% finished apps. The goal of every tutorial is to teach as much as possible. If I tried to make 100% perfect apps these videos would get to be very boring and would have a ton of repetition. I’m sorry I didn’t explain that earlier. By the end, you’ll be able to make just about any type of app you can imagine and it will work on most every device.

  7. Anonymous says:

    Hi, Derek.
    First off, I would like to say that I appreciate you making your tutorials and they have taught me quite a bit.
    But I have stumbled upon a problem running the final tip calculator.
    Your code seems to work fine but mine doesn’t. I am very confident it is not a syntax error because I have thoroughly compared your code to mine. Plus the eclipse syntax error checker doesn’t report any errors. The XML layout file is similar, the only difference is I changed the name of some strings for learning purposes, ex.bill_text_view is changed to text_view_bill. Your code works fine on my emulator but mine doesn’t.
    Any thoughts?
    Thanks in advance:)

    Logcat

    06-29 09:26:34.349: D/dalvikvm(2602): GC_CONCURRENT freed 75K, 7% free 2649K/2840K, paused 9ms+3ms, total 120ms
    06-29 09:26:35.668: W/Trace(2602): Unexpected value from nativeGetEnabledTags: 0
    06-29 09:26:35.689: W/Trace(2602): Unexpected value from nativeGetEnabledTags: 0
    06-29 09:26:35.699: W/Trace(2602): Unexpected value from nativeGetEnabledTags: 0
    06-29 09:26:35.848: W/Trace(2602): Unexpected value from nativeGetEnabledTags: 0
    06-29 09:26:36.209: W/Trace(2602): Unexpected value from nativeGetEnabledTags: 0
    06-29 09:26:36.219: W/Trace(2602): Unexpected value from nativeGetEnabledTags: 0
    06-29 09:26:36.219: W/Trace(2602): Unexpected value from nativeGetEnabledTags: 0
    06-29 09:26:36.228: D/AndroidRuntime(2602): Shutting down VM
    06-29 09:26:36.228: W/dalvikvm(2602): threadid=1: thread exiting with uncaught exception (group=0xb2c76908)
    06-29 09:26:36.339: D/dalvikvm(2602): GC_CONCURRENT freed 49K, 6% free 2987K/3148K, paused 8ms+2ms, total 85ms
    06-29 09:26:36.339: E/AndroidRuntime(2602): FATAL EXCEPTION: main
    06-29 09:26:36.339: E/AndroidRuntime(2602): java.lang.NumberFormatException: Invalid double: “&.02f”
    06-29 09:26:36.339: E/AndroidRuntime(2602): at java.lang.StringToReal.invalidReal(StringToReal.java:63)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at java.lang.StringToReal.parseDouble(StringToReal.java:269)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at java.lang.Double.parseDouble(Double.java:295)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at com.doublea.tipcalcapp.TipCalcApp.updateTipAndFinalBill(TipCalcApp.java:198)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at com.doublea.tipcalcapp.TipCalcApp.access$1(TipCalcApp.java:195)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at com.doublea.tipcalcapp.TipCalcApp$7.onItemSelected(TipCalcApp.java:360)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at android.widget.AdapterView.fireOnSelected(AdapterView.java:892)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at android.widget.AdapterView.access$200(AdapterView.java:49)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at android.widget.AdapterView$SelectionNotifier.run(AdapterView.java:860)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at android.os.Handler.handleCallback(Handler.java:725)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at android.os.Handler.dispatchMessage(Handler.java:92)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at android.os.Looper.loop(Looper.java:137)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at android.app.ActivityThread.main(ActivityThread.java:5039)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at java.lang.reflect.Method.invokeNative(Native Method)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at java.lang.reflect.Method.invoke(Method.java:511)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
    06-29 09:26:36.339: E/AndroidRuntime(2602): at dalvik.system.NativeStart.main(Native Method)

    • Derek Banas says:

      If you catch the NumberFormatException everything should be fine. When I was making these tutorials, my goal was to cover as much as possible, but not to necessarily make a perfect app. I’m sorry if you thought I was. As the tutorials progress the apps will be more professionally done, but I didn’t want to waste space constantly catching exceptions and then debugging every single thing that could go wrong. I thought that would make the videos boring and spoil the fun.

      I hope that explains everything

      • Anonymous says:

        Thanks for taking the time to reply:)
        I understand that you are not making full apps that can go on the market and I don’t expect you too. I understand that the apps are built for educational purposes and to teach the workflow which I appreciate. I look at your tutorials/apps in a way were I will learn the concepts and real life examples of what you are saying. After you finish an app, I will try to add on to it to make it more advanced and as practice. I am trying to add more to this tip calculator but I have a error that I have been trying to solve for days. I could just use your code and add on to that but I want to know why my code doesn’t work so that I don’t come across this problem in the future. Once the apps get really advanced and complicated, it might not be an easy fix like it possibly could be now.

      • Anonymous says:

        Thanks for taking the time to reply:)
        I understand that you are not making full apps that can go on the market and I don’t expect you too. I understand that the apps are built for educational purposes and to teach the workflow which I appreciate. I look at your tutorials/apps in a way were I will learn the concepts and real life examples of what you are saying. After you finish an app, I will try to add on to it to make it more advanced and as practice. I am trying to add more to this tip calculator but I have a error that I have been trying to solve for days. I could just use your code and add on to that but I want to know why my code doesn’t work so that I don’t come across this problem in the future. Once the apps get really advanced and complicated, it might not be an easy fix like it possibly could be now.
        I did catch the NumberFormatException but my app still crashes.
        The emulator says unfortunately “app” has crashed.
        Could it be something in the manifest file, you didn’t post that.
        I really want to know what the problem is so it doesn’t happen again.

        I don’t expect you to thoroughly examine my code but I will post it just to help.

        Thank you in advance:)
        I really appreciate you making these tutorials and helping me.
        Again, I don’t expect you to examine my code and make fixing my problem your highest priority. But if you could point me to the right direction I would highly appreciate it.

        java file

        package com.doublea.tipcalcapp;

        import android.os.Bundle;
        import android.os.SystemClock;
        import android.app.Activity;
        import android.text.Editable;
        import android.text.TextWatcher;
        import android.view.Menu;
        import android.view.View;
        import android.view.View.OnClickListener;
        import android.widget.AdapterView;
        import android.widget.AdapterView.OnItemSelectedListener;
        import android.widget.Button;
        import android.widget.CheckBox;
        import android.widget.Chronometer;
        import android.widget.CompoundButton;
        import android.widget.EditText;
        import android.widget.RadioButton;
        import android.widget.RadioGroup;
        import android.widget.RadioGroup.OnCheckedChangeListener;
        import android.widget.SeekBar;
        import android.widget.SeekBar.OnSeekBarChangeListener;
        import android.widget.Spinner;
        import android.widget.TextView;

        public class TipCalcApp extends Activity {

        private static final String BILL_TOTAL=”BILL_TOTAL”;
        private static final String TIP_CURRENT=”TIP_CURRENT”;
        private static final String BILL_WITHOUT_TIP=”BILL_WITHOUT_TIP”;

        private double billBeforeTip; // Users bill before tip
        private double tipAmount; // Tip amount
        private double finalBill; // Bill plus Tip

        EditText billBeforeTipET;
        EditText tipAmountET;
        EditText finalBillET;

        // NEW PART —————

        // Sum of all radio buttons and check boxes

        private int[] checklistValues = new int[12];

        // Declare CheckBoxes

        CheckBox friendlyCheckBox;
        CheckBox specialsCheckBox;
        CheckBox opinionCheckBox;

        // Declare RadioButtons

        RadioGroup availableRadioGroup;
        RadioButton availableBadRadio;
        RadioButton availableOKRadio;
        RadioButton availableGoodRadio;

        // Declare Spinner (Drop Down Box)

        Spinner problemsSpinner;

        // Declare Buttons

        Button startChronometerButton;
        Button pauseChronometerButton;
        Button resetChronometerButton;

        // Declare Chronometer

        Chronometer timeWaitingChronometer;

        // The number of seconds you spent
        // waiting for the waitress

        long secondsYouWaited = 0;

        // TextView for the chronometer

        TextView timeWaitingTextView;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tip_calc_app);

        if(savedInstanceState == null){

        billBeforeTip = 0.0;
        tipAmount = .15;
        finalBill = 0.0;

        }else{

        billBeforeTip = savedInstanceState.getDouble(BILL_WITHOUT_TIP);
        tipAmount = savedInstanceState.getDouble(TIP_CURRENT);
        finalBill = savedInstanceState.getDouble(BILL_TOTAL);

        }

        billBeforeTipET = (EditText) findViewById(R.id.EditTextBill);
        tipAmountET = (EditText) findViewById(R.id.EditTextTip);
        finalBillET = (EditText) findViewById(R.id.EditTextFinalBill);

        tipSeekBar = (SeekBar) findViewById(R.id.ChangeTipSeekBar);

        tipSeekBar.setOnSeekBarChangeListener(tipSeekBarListener);

        billBeforeTipET.addTextChangedListener(billBeforeTipListener);

        friendlyCheckBox = (CheckBox) findViewById(R.id.FriendlyCheckBox);
        specialsCheckBox =(CheckBox) findViewById(R.id.SpecialsCheckBox);
        opinionCheckBox = (CheckBox) findViewById(R.id.OpinionCheckBox);

        setupIntroCheckBoxes();

        availableRadioGroup = (RadioGroup) findViewById(R.id.AvailableRadioGroup);
        availableBadRadio = (RadioButton) findViewById(R.id.AvailableBadRadio);
        availableBadRadio = (RadioButton) findViewById(R.id.AvailableOKRadio);
        availableGoodRadio = (RadioButton) findViewById(R.id.AvailableGoodRadio);

        addChangeListenerToRadio();

        problemsSpinner = (Spinner) findViewById(R.id.ProblemsSpinner);

        addItemSelectedListenerToSpinner();

        timeWaitingChronometer = (Chronometer) findViewById(R.id.TimeWaitingChronometer);
        startChronometerButton = (Button) findViewById(R.id.StartChronoButton);
        pauseChronometerButton = (Button) findViewById(R.id.PauseChronoButton);
        resetChronometerButton = (Button) findViewById(R.id.ResetChronoButton);

        setButtonOnClickListeners();

        timeWaitingTextView = (TextView) findViewById(R.id.TimeWaitingTextView);

        }

        private TextWatcher billBeforeTipListener = new TextWatcher(){

        @Override
        public void afterTextChanged(Editable s) {
        // TODO Auto-generated method stub

        }

        @Override
        public void beforeTextChanged(CharSequence s, int start,
        int count, int after) {
        // TODO Auto-generated method stub

        }

        @Override
        public void onTextChanged(CharSequence s, int start,
        int before, int count) {

        try {

        billBeforeTip = Double.parseDouble(s.toString() );

        } catch (NumberFormatException e) {

        billBeforeTip = 0.0;

        }

        updateTipAndFinalBill();

        }

        };

        private void updateTipAndFinalBill(){

        tipAmount = Double.parseDouble(tipAmountET.getText().toString() );

        finalBill = billBeforeTip + (billBeforeTip * tipAmount);

        finalBillET.setText(String.format(“%.02f”, finalBill));

        }

        @Override
        protected void onSaveInstanceState(Bundle outState){

        super.onSaveInstanceState(outState);

        outState.putDouble(BILL_TOTAL, finalBill);

        outState.putDouble(TIP_CURRENT, tipAmount);

        outState.putDouble(BILL_WITHOUT_TIP, billBeforeTip);

        }

        private SeekBar tipSeekBar;

        private OnSeekBarChangeListener tipSeekBarListener = new OnSeekBarChangeListener(){

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress,
        boolean fromUser) {

        tipAmount = (tipSeekBar.getProgress()) * .01;

        tipAmountET.setText(String.format(“%.02f”, tipAmount));

        updateTipAndFinalBill();

        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
        // TODO Auto-generated method stub

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }

        };

        private void setupIntroCheckBoxes(){
        friendlyCheckBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener(){

        @Override
        public void onCheckedChanged(CompoundButton buttonView,
        boolean isChecked) {

        checklistValues[0]= (friendlyCheckBox.isChecked())?4:0;

        setTipFromWaitressChecklist();

        updateTipAndFinalBill();
        }
        });

        specialsCheckBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener(){

        @Override
        public void onCheckedChanged(CompoundButton buttonView,
        boolean isChecked) {

        checklistValues[1]= (specialsCheckBox.isChecked())?1:0;

        setTipFromWaitressChecklist();

        updateTipAndFinalBill();
        }
        });

        opinionCheckBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener(){

        @Override
        public void onCheckedChanged(CompoundButton buttonView,
        boolean isChecked) {

        checklistValues[2]= (opinionCheckBox.isChecked())?2:0;

        setTipFromWaitressChecklist();

        updateTipAndFinalBill();
        }
        });

        }

        private void setTipFromWaitressChecklist(){

        int checklistTotal = 0;

        for(int item : checklistValues){

        checklistTotal += item;

        }

        tipAmountET.setText(String.format(“&.02f”, checklistTotal * .01));

        }

        private void addChangeListenerToRadio(){

        availableRadioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener(){

        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {

        checklistValues[3]= (availableBadRadio.isChecked())?-1:0;

        checklistValues[4]= (availableBadRadio.isChecked())?2:0;

        checklistValues[5]= (availableGoodRadio.isChecked())?4:0;

        setTipFromWaitressChecklist();

        updateTipAndFinalBill();

        }

        });

        }

        private void addItemSelectedListenerToSpinner(){

        problemsSpinner.setOnItemSelectedListener(new OnItemSelectedListener(){

        @Override
        public void onItemSelected(AdapterView arg0, View arg1,
        int arg2, long arg3) {

        checklistValues[6]= (problemsSpinner.getSelectedItem()).equals(“Bad”)?-1:0;

        checklistValues[7]= (problemsSpinner.getSelectedItem()).equals(“OK”)?3:0;

        checklistValues[8]= (problemsSpinner.getSelectedItem()).equals(“Bad”)?6:0;

        setTipFromWaitressChecklist();

        updateTipAndFinalBill();

        }

        @Override
        public void onNothingSelected(AdapterView arg0) {

        }

        });

        }

        private void setButtonOnClickListeners(){

        startChronometerButton.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View v) {

        int stoppedMilliseconds = 0;

        String chronoText = timeWaitingChronometer.getText().toString();

        String array[] = chronoText.split(“:”);

        if (array.length == 2 ){

        stoppedMilliseconds = Integer.parseInt(array[0]) * 60 * 1000 +
        Integer.parseInt(array[1]) * 1000;

        } else if (array.length == 3){

        stoppedMilliseconds = Integer.parseInt(array[0]) * 60 * 60 * 1000 +
        Integer.parseInt(array[1]) * 60 * 1000 +
        Integer.parseInt(array[2]) * 1000;

        }

        timeWaitingChronometer.setBase(SystemClock.elapsedRealtime() – stoppedMilliseconds);

        secondsYouWaited = Long.parseLong(array[1]);

        updateTipBasedOnTimeWaited(secondsYouWaited);

        timeWaitingChronometer.start();
        }

        });

        pauseChronometerButton.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View v) {

        timeWaitingChronometer.stop();

        }

        });

        resetChronometerButton.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View v) {

        timeWaitingChronometer.setBase(SystemClock.elapsedRealtime());

        secondsYouWaited = 0;

        }
        });

        }

        private void updateTipBasedOnTimeWaited(long secondsWaited){

        checklistValues[9]= (secondsWaited > 10)?-2:2;

        setTipFromWaitressChecklist();

        updateTipAndFinalBill();

        }

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.tip_calc_app, menu);
        return true;
        }

        }

        manifest

        • Anonymous says:

          Manifest

        • Derek Banas says:

          Thank you for being so understanding. Another thing that came up is a problem were people are entering commas in the price amount instead of decimals. I never expected that, but I guess it is common practice in some countries.

          A few other fixes have been posted here by some kind people. Ill take a look at them.

          Thanks for stopping by my website :)
          Derek

        • Alvaro says:

          I think I know where your getting your error from:

          tipAmountET.setText(String.format(“&.02f”, checklistTotal * .01));

          The right syntax would be :

          “(String.format(“%.02f”, checklistTotal * .01)

          Regards

  8. Adam says:

    I have a problem with setButtonClickListeners()

    I get an error, “setOnClickListener(View.onClickListener) in the type View is not applicable for the arguments (new dialogueInterface.onClickListener(){})

    I have typed in exactly the code you have. Any idea what is causing this?

    • Derek Banas says:

      Did you try downloading and importing the whole Android package into Eclipse? I provide that on this page. That will eliminate any typos that may have come up.

      You could then compare my code to yours with this Difference Checker to find the differences. I hope that helps. If not tell me

  9. Johnny says:

    Hi Derek Banas, really enjoy this tutorials, fantastic indeed!!! Can we expect SQLite connection in ANDROID anytime soon?

    Regards,
    J.

  10. Nick says:

    Stunning tutorials Mr Banas!
    I really like your style and enthusiasm. And your attention to detail and the way you are thinking about how the info is coming across.
    In the 90s I did a course on object oriented programming with the Open University in London. The language they used for the course was Smalltalk. I found it very intuitive and elegant. The course now uses Java.
    I jumped back into programming a few weeks ago because I want to make some apps.
    I have found your videos to be the most well put together. And they have helped me learn the complexities of Java, among other things.
    Have you played with Smalltalk?
    All the best, Nick

    • Derek Banas says:

      Hi Nick,

      Yes I used smalltalk in the past. That was the language used originally when all of the great design patterns were discovered. It is very fun to use.

      As you said I mainly use Java and C++ now because of the modern libraries available.

      I plan on making Android tutorials through the rest of the year. I hope you enjoy them :)

      Derek

  11. Vladislav says:

    I can easily run this app with emulator but it doesn’t launch on my HTC Desire C with 4.0.3 IceCreamSandwich. What’s wrong?

  12. Josias says:

    Hi, i have tired the app for differents emulators and it runs normally, without any problem. But when i tried to run it in my phone, it doesn’t work. The message i get is: “CrazyTipCalc have stoped”.
    If i use your code, is the same problem. I tried to track it with the LogCat but the intarface is really confusing and i don’t know how to use it. My phone is a samsung galaxy young, but i have read the comment of ‘Vladislav’ that have my same problem with another phone. Can you help me, please :(

  13. Chris says:

    Hello Derek,

    Great tutorials and thanks very much for posting them! I am still learning all of this so excuse me if I am missing something obvious. After finishing Tutorial 5, everything runs fine for me in my emulator through eclipse, however the Tip amount seems to be incorrect.

    For example, if I set the tip at 15% (0.15) and then I click the friendly check box, instead of changing the tip to 19% it goes down to 4%. So it seems that instead of adding to the existing tip, it erases the tip and gives it the value of the check box.

    Sometimes it works fine when I already have other boxes and radios selected but most of the time it works as stated above.

    Am I missing something?

    thanks again!

  14. Chris says:

    After watching the end of your tutorial again, yours works the same way mine does. I figured it would take whatever tip you initially set and then add or subtract values to it based on your waitresses performance.

    I tried changing the method slightly but this doesn’t work, it always adds to the tip and never subtracts but I was thinking something like this:


    private void setTipFromWaitressCheckList(){

    int checklistTotal = 0;
    double tipAmount = Double.parseDouble(tipAmountET.getText().toString());

    for(int item : checklistValues){

    checklistTotal += item;

    }

    tipAmountET.setText(String.format("%.02f", tipAmount + (checklistTotal * .01)));

    }

    </code

  15. Chris says:

    either way good stuff, thanks Derek

    (no way for me to edit my previous posts or I would do so)

    :)

    Keep them coming!

  16. Jenton Lee says:

    Amazing tutorials Derek! The amount of time you put into making these videos and your humorous and casual speaking style make this series the best Android tutorials I’ve found on the web.

    Quick question on the chronometer and the stoppedMilliseconds stuff in the code.

    —-
    if (array.length == 2) {
    // Find the seconds
    stoppedMilliseconds = Integer.parseInt(array[0]) * 60 * 1000
    + Integer.parseInt(array[1]) * 1000;

    Questions: (formatted in a list for organization’s sake)
    - Isn’t array[0] always going to be 00 in this case? If so, why do we need to add the array[0] calculations?
    - Also, is the “else if (array.length == 3)” only for when the chronometer gets up to the hours range?
    - Lastly, I’m confused as to why we need to keep track of the stoppedMilliseconds. It looks as if this tip calculator only uses the secondsYouWaited variable to change the tip. What purpose does “timeWaitingChronometer.setBase(SystemClock.elapsedRealtime() – stoppedMilliseconds);” serve?

    Sorry for the massive wall of questions, no worries if you don’t have the time to address them. Either way, thanks a million for doing these tutorials!!!

    -Jenton

    • Jenton Lee says:

      ohhhh, nevermind! I see why we need the stoppedMilliseconds. I commented out “timeWaitingChronometer.setBase(SystemClock.elapsedRealtime() – stoppedMilliseconds);” and ran the app. Once I hit the pause button, and then the start button, the chronometer didn’t pick up where it left off, it added on the time that had elapsed from when I hit pause, to when I hit start.

      So we need to keep track of the stoppedMilliseconds so that when you pause and start, the chronometer will count up properly!

      #themoreyouknow

      Is it strange that this feature is not already built into the chronometer though? Seems like a bit of effort just to implement a pause and start function correctly.

      • Derek Banas says:

        Sorry I couldn’t get to you quicker. Yes the chronometer is completely strange and kind of broken. I tried to fix it in this tutorial because someone asked me to. You won’t use it all that much in the real world, but here it is if you need it :)

        I’m glad you fixed the error.

  17. Anonymous says:

    i have the problem that when i click on the Checkbox the app stops to work and logcat shows me that “0.04″ is not a double value a little bit strange.
    So i get an NumberFormatExceptionError in the line :

    double tip = Double.parseDouble(tipET.getText().toString());

  18. LuvLinuxOS says:

    Hey Derek,

    Again you are doing a fantastic job!!! I just want to post that working through this programs with you it the best way! Yes the cheat sheets are cool but seeing all the nuances of Eclipse is even better. Plus I am coding in an updated Eclipse using the latest version of Android SDK on Linux. Hey keep up the good work and start publishing some Open Source Videos!!!

    Be Blessed!!!

    Elbennit

  19. Alan says:

    Thanks Derek for all the videos, it’s realy helpfull.

  20. SlackerSpace says:

    Hi Derek,

    I like the tutorials so far. They’re a great resource in learning android development! So, it is in the interest of clarification for others that I want to point out a mistake in your explanation of the time read out from the chronometer. The math and the results are right, but the explanation in your comments and the video is a little off.

    What you’re doing is converting the output of the chronometer into milliseconds. The output of the chronometer will either take the form MM:SS or H:MM:SS. When you split these strings you are getting an array that looks like:

    array[0] = MM
    array[1] = SS

    or in the case of 3 array elements

    array[0] = H
    array[1] = MM
    array[2] = SS

    This explains why the math you have makes sense. You are converting hours (*60*60*1000), minutes(*60*1000), and seconds(*1000) into milliseconds. You are not, as is stated above, “finding the seconds” or “finding the minutes” and array[2] does not hold minutes, it holds seconds.

    Anyway, I hope that clears things up for anyone that was confused.

    Cheers!

    • SlackerSpace says:

      I also noticed that this misunderstanding of the chronometer output causes a couple of bugs in the code.

      Neither are a big issue, especially since, as you said, you’re just looking to test the code against an arbitrarily short length of time (10 seconds).

      The first bug shows up if you let the code run for more than a minute.


      secondsYouWaited = Long.parseLong(array[1]);

      The seconds will loop around after you hit one minute and the app will give the waitress a bigger tip if she makes you wait for between 1:00 and 1:10 – and for the first ten seconds of every minute afterwards.

      The second bug will show up only after letting the timer run for over an hour. That will change the output to H:MM:SS and the 3 element array case. This will mean that in the above assignment array[1] isn’t even referring to the seconds anymore it is now referring to the minutes since the past hour – giving the waitress a bigger tip if she makes you wait between 1 hour and 1 hour and 10 minutes.

      Like you’ve said in other comments, the point of these apps is not to write fool-proof code. Neither of these bugs are major nor will they impact the performance of the app for short tests (under a minute), however, as they are a result of a fundamental misunderstanding of one of the widgets you’re using and not just simplified code for instructional purposes, I thought I’d point them out.

      Cheers!

      • Derek Banas says:

        Thank you for posting that information and for understanding the point of this code. I largely write this stuff out of my head with the specific goal of covering as much as possible while also not spending to much time reviewing what I think is understood.

        I do thank you once again for pointing that bug out though :)

    • Derek Banas says:

      Thank you very much for the input and help :) Some times my mouth gets ahead of the brain.

  21. Apoorv says:

    Thanks Derek for these videos. I have a doubt regarding the layout, eclipse has different layout compared to emulator. Like there was a lot of space between checkbox buttons and radiogroup in the emulator. Does it have to do with what device we are choosing in the emulator?

    I have one more doubt my application complied and got installed on the emulator but when i am running the application it is crashing. I did uninstall the previous version of the app can you tell me why is it happening, i also checked it on the real devices. Thanks in advance

    • Derek Banas says:

      In part 26 of my Android tutorial I cover how to install the new Android software. That may help correct those problems. Also try the packages I provide. I have tested them.

      • Apoorv says:

        Thanks for the reply. I have updated my software as shown in the Tutorial-26 but still the problem persists. I can execute your package/code successfully on my machine. So now i am very confused why is that happening as i have followed everything from your tutorial. The same thing is happening with other stock-quote app also.

  22. kk says:

    thank you for your tutorial.
    I wanna ask if i want to disable the start button after I clicked start. what should i do? It is becoz I notice that if I continuously click start, the timer will freeze.

  23. Daryl says:

    Hi Derek Banas,

    Thanks for your great tutorial!

    I’ve one problem in a R.java file. The problem is in the R.java/R/array file… problems is in this line:

    public static final int problem-solving=0x7f060000

    The Error is: Syntax error on token “-”, , expected

    I don’t know what to do, so if someone could please help me out?

  24. Walter Reyes says:

    What a great tutorial, Derek!
    I like that you explain everything with a developer perspective. You dont stop in basic concepts of JAVA, which is what I was looking for.

    I am planning to finish the whole series

    Thank you very much!

  25. Shikha says:

    Hi Derek,
    One small problem in general but finding it very difficult to solve.
    How to copy this CrazyTipCalc project into other project in eclipse.
    Tried everything from Copying the folder manually and changing the name to
    Copying the CrazyTipCalc project in eclipse and pasting it.

    Please tell how you do the same.

  26. Klaus says:

    Hi Derek,
    all of this is quite new for me. While I was searching for an tutorial for Andriod Studio yours came up. It’s smart, very professional and useful.
    But there is a problem, which I can’t figure out by myself. The App starts and closes right away. I think, it’ the Double.parse in line 233.
    In the “lodcat” I get this: java.lang.NumberFormatException: Invalid double: “0,00″.
    I would be greatful for a hint ;-)!

    Thank you and keep up the exellent stuff!

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Google+