Sunday, May 1, 2011

Creating an Android Calculator Tutorial

Through this tutorial you will learn how to develop and code a simple calculator in Android. Topics covered will include using a webview, layouts, and button listeners.

Introduction

One of the cool things about having a smart phone is knowing that you will always have a calculator handy. If you need to total receipts, perform some supermarket comparisons, or calculate tips or percentages on the fly a calculator is definitely a handy tool.

Screenshot of the calculator tutorial
However, the basic calculator app that comes preloaded with the Android Operating system leaves a lot to be desired. Perhaps you want to build your own more advanced calculator. You can use this tutorial as a starting point.



The Layout

This layout could admittedly be improved upon. The focus of this tutorial is about bringing together all of the pieces rather than creating a beautiful looking program, so we really just want something functional. Listed below is the xml code for the layout.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    
    <WebView 
        android:id="@+id/webview"
        android:layout_width="fill_parent" android:layout_height="50dip"/>
    
    <LinearLayout android:id="@+id/linearLayout1" android:layout_width="fill_parent" android:layout_height="wrap_content">
        <Button android:layout_height="wrap_content" android:id="@+id/buttonLeftParen" android:text="(" android:layout_weight="1" android:layout_width="fill_parent"></Button>
        <Button android:layout_height="wrap_content" android:id="@+id/buttonRightParen" android:text=")" android:layout_weight="1" android:layout_width="fill_parent"></Button>
        <Button android:layout_height="wrap_content" android:id="@+id/buttonBackspace" android:layout_weight="1" android:text="B" android:layout_width="fill_parent"></Button>
        <Button android:layout_height="wrap_content" android:id="@+id/buttonClear" android:text="C" android:layout_weight="1" android:layout_width="fill_parent"></Button>
    </LinearLayout>
    <LinearLayout android:id="@+id/linearLayout2" android:layout_width="fill_parent" android:layout_height="wrap_content">
        <Button android:layout_height="wrap_content" android:id="@+id/button7" android:text="7" android:layout_weight="1" android:layout_width="fill_parent"></Button>
        <Button android:layout_height="wrap_content" android:id="@+id/button8" android:text="8" android:layout_weight="1" android:layout_width="fill_parent"></Button>
        <Button android:layout_height="wrap_content" android:id="@+id/button9" android:text="9" android:layout_weight="1" android:layout_width="fill_parent"></Button>
        <Button android:layout_height="wrap_content" android:id="@+id/buttonPlus" android:text="+" android:layout_weight="1" android:layout_width="fill_parent"></Button>
    </LinearLayout>
    <LinearLayout android:id="@+id/linearLayout3" android:layout_width="fill_parent" android:layout_height="wrap_content">
        <Button android:layout_height="wrap_content" android:id="@+id/button4" android:text="4" android:layout_weight="1" android:layout_width="fill_parent"></Button>
        <Button android:layout_height="wrap_content" android:id="@+id/button5" android:text="5" android:layout_weight="1" android:layout_width="fill_parent"></Button>
        <Button android:layout_height="wrap_content" android:id="@+id/button6" android:text="6" android:layout_weight="1" android:layout_width="fill_parent"></Button>
        <Button android:layout_height="wrap_content" android:id="@+id/buttonMinus" android:text="-" android:layout_weight="1" android:layout_width="fill_parent"></Button>
    </LinearLayout>
    <LinearLayout android:id="@+id/linearLayout4" android:layout_width="fill_parent" android:layout_height="wrap_content">
        <Button android:layout_height="wrap_content" android:id="@+id/button1" android:text="1" android:layout_weight="1" android:layout_width="fill_parent"></Button>
        <Button android:layout_height="wrap_content" android:id="@+id/button2" android:text="2" android:layout_weight="1" android:layout_width="fill_parent"></Button>
        <Button android:layout_height="wrap_content" android:id="@+id/button3" android:text="3" android:layout_weight="1" android:layout_width="fill_parent"></Button>
        <Button android:layout_height="wrap_content" android:id="@+id/buttonTimes" android:text="*" android:layout_weight="1" android:layout_width="fill_parent"></Button>
    </LinearLayout>
    <LinearLayout android:id="@+id/linearLayout5" android:layout_width="fill_parent" android:layout_height="wrap_content">
        <Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:layout_weight="1" android:id="@+id/button0" android:text="0"></Button>
        <Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:layout_weight="1" android:id="@+id/buttonDecimal" android:text="."></Button>
        <Button android:layout_height="wrap_content" android:layout_width="fill_parent" android:layout_weight="1" android:id="@+id/buttonEquals" android:text="="></Button>
        <Button android:layout_height="wrap_content" android:id="@+id/buttonDivide" android:text="/" android:layout_width="fill_parent" android:layout_weight="1"></Button>
    </LinearLayout>
    
</LinearLayout>

The layout is pretty straightforward, a bunch of rows with buttons in them. This layout uses a combination of linear layouts, whereas a table layout could also be suited.

As I mentioned in my layout tutorial, it is often a good idea to sketch out what you want beforehand, because it is much easier to make changes on paper and make the XML once. Regretfully, I did not follow my own advice when I wrote this tutorial...

The Secret

So know we have a bunch of buttons that we can use to have the user add input, but how do we actually crunch the numbers? Remember the "Golden Rule" of programming. Reuse code and don't try to reinvent the wheel!

The display at the top is actually a WebView. Using a webview instead of a TextView gives us extra formatting options, and also allows us to leverage the power of JavaScript.

JavaScript has a built in "eval" function that will take a string as an argument and run that string as JavaScript code. Our string will just be a bunch of math that we want to compute, and JavaScript will handle all the work for us.

Enabling JavaScript for the WebView

It is important to note that the WebView by default does not have javascript enabled. Use the code below to enable JavaScript in the WebView.

// Enable javascript for the view
mWebView = (WebView) findViewById(R.id.webview);
mWebView.getSettings().setJavaScriptEnabled(true);


Button Listeners and String Builders

The calculator works by storing the user inputs in a String Builder and passing this information to the web view for evaluation. StringBuilders are used instead of strings because they are more efficient when you are constantly changing values.

We will use one button listener for all of the buttons. For most of the buttons, what we want to append to the string is exactly what the button is displaying. This makes the listener code fairly simple.

private class ButtonClickListener implements OnClickListener {

@Override
public void onClick(View v) {
 switch (v.getId()) {
 case R.id.buttonBackspace:
  if(mMathString.length() > 0)
   mMathString.deleteCharAt(mMathString.length()-1);
  break;
 case R.id.buttonClear:
  if(mMathString.length() > 0)
   mMathString.delete(0, mMathString.length());
  break;
 default:
  mMathString.append(((Button) v).getText());
 }
 
 updateWebView();
}




Updating the WebView

You will notice that the listener calls a function to update the web view. This function creates a simple string of html to display everytime it is called. I believe there is a way to more fully integrate the JavaScript handler with the Android App, but for the small amount of computation we are doing it is probably not worth it right now.

private void updateWebView() {
 
 StringBuilder builder = new StringBuilder();
 
 builder.append("<html><body>");
 builder.append("<script type=\"text/javascript\">document.write('");
 builder.append(mMathString.toString());
 builder.append("');");
 builder.append("document.write('<br />=' + eval(\"");
 builder.append(mMathString.toString());
 builder.append("\"));</script>");
 builder.append("</body></html>");

 mWebView.loadData(builder.toString(), "application/xhtml", "UTF-8");


I tried to split up the building of the string into smaller chunks in order to improve readability. As you can see, it can get pretty difficult to read fairly quickly.

The App in Action

Listed below is a screenshot from the app.

A screenshot of the calculator evaluating an expression


There are a number of areas in which this app could be improved, and if there is interest, I may do a follow up tutorial.

  • Design a better layout
  • Format the output better
  • Free text input
  • More advanced math functions (sine, cosine, etc...)
Thanks for checking out my tutorial. Please leave feedback and follow the blog!

Full Code for Activity

Listed below is the full code for the activity.

package com.androiddom.calculatortest;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.WebView;
import android.widget.Button;

public class CalculatorActivity extends Activity {
 
 private WebView mWebView;
 private StringBuilder mMathString;
 private ButtonClickListener mClickListener;
 
 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  
  // Create the math string
  mMathString = new StringBuilder();
  
  // Enable javascript for the view
  mWebView = (WebView) findViewById(R.id.webview);
  mWebView.getSettings().setJavaScriptEnabled(true);
  
  // Set the listener for all the buttons
  mClickListener = new ButtonClickListener();
  int idList[] = { R.id.button0, R.id.button1, R.id.button2,
    R.id.button3, R.id.button4, R.id.button5, R.id.button6,
    R.id.button7, R.id.button8, R.id.button9, R.id.buttonLeftParen,
    R.id.buttonRightParen, R.id.buttonPlus, R.id.buttonPlus,
    R.id.buttonMinus, R.id.buttonDivide, R.id.buttonTimes,
    R.id.buttonDecimal, R.id.buttonBackspace, R.id.buttonClear };

  for(int id : idList) {
   View v = findViewById(id);
   v.setOnClickListener(mClickListener);
  }

 }
 
 private void updateWebView() {
  
  StringBuilder builder = new StringBuilder();
  
  builder.append("<html><body>");
  builder.append("<script type=\"text/javascript\">document.write('");
  builder.append(mMathString.toString());
  builder.append("');");
  builder.append("document.write('<br />=' + eval(\"");
  builder.append(mMathString.toString());
  builder.append("\"));</script>");
  builder.append("</body></html>");

  mWebView.loadData(builder.toString(), "application/xhtml", "UTF-8");
 }

 private class ButtonClickListener implements OnClickListener {

  @Override
  public void onClick(View v) {
   switch (v.getId()) {
   case R.id.buttonBackspace:
    if(mMathString.length() > 0)
     mMathString.deleteCharAt(mMathString.length()-1);
    break;
   case R.id.buttonClear:
    if(mMathString.length() > 0)
     mMathString.delete(0, mMathString.length());
    break;
   default:
    mMathString.append(((Button) v).getText());
   }
   
   updateWebView();
  }

 }



------------------------------------------------------------

We create these tutorials in our free time. If you like what you see please consider buying us a cup of coffee so we can keep creating useful material. Click on the image below to make a donation via Paypal.

63 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. I can not see the numbers on the WebView. I need to install some plugin?

    Thank you.
    Diego, Brazil

    ReplyDelete
  3. i want to create an html app which should work as an app but offline. It shouldnot connect to internet. Please help me..
    My mail id is shyjumon.thomas@gmail.com.

    ReplyDelete
  4. hi thanks...
    I can not see the numbers on the WebView...its not working help me my mail id:karthiktokeyan@gmail.com

    ReplyDelete
  5. Hi Karthik,

    Do you get any compiler errors? Or any other messages?

    ReplyDelete
  6. THANK YOU! :) - racrecio

    ReplyDelete
  7. Thanks for the cool post

    ReplyDelete
  8. im not getting any no. on tht pad help me pla my emailid is penubarthy@gmail.com and im not gtng any compile time errors

    ReplyDelete
  9. im not getting any numbers too on webview. can someone help me? email: mikac.matija@gmail.com tnx

    ReplyDelete
  10. thnxx man..dat did d work fa me..

    ReplyDelete
  11. Hi, Thanks for the Post. :) But I am getting Null pointer exception in the activityFile at line no 27 . that is while doingmWebView.getSettings() , I think (WebView) findViewById(R.id.webview); is returning NULL. I am not getting whats the problem. Can ANyone help me?? My email Id is sachinpattan@gmail.com

    ReplyDelete
  12. really superb man... thanks for posting .. can u pls send some examples coding and especially virtual keyboard in andriod ...to me my mail adress is renganarundx@gmail.com

    ReplyDelete
  13. Give me the same thing using textview instead of webview

    ReplyDelete
  14. Nice tutorial.. but what will it do when i press equals? ... i mean i have case R.id.buttonEquals:
    mMathString.
    break;

    what is behind mMathString?

    ReplyDelete
    Replies
    1. mMathString like its name describes is just a string.
      We are using Javascript to do the operations for us:
      "JavaScript has a built in "eval" function that will take a string as an argument and run that string as JavaScript code. Our string will just be a bunch of math that we want to compute, and JavaScript will handle all the work for us."

      So, basically we are passing a string to javascript and it returns the result.

      Delete
    2. Great, awesome logic used simplifies the program greatly !Keep it up, loved the logic u used because normally doing it using a single view will take tons of code !

      Delete
  15. Great tut! Thanks a lot! :D

    ReplyDelete
    Replies
    1. You are welcome, glad it helped.

      Delete
  16. when i copy the code in eclipse it gives me an error on all the R.id's it puts the red line under id help

    ReplyDelete
    Replies
    1. Do you have your android sdk properly set up?
      R is a generated class, if eclipse is set up properly with the sdk it should work.

      Delete
    2. go to eclipse and select Project nd select Build All option.
      Then that error will be deleted

      Delete
  17. im not getting any no. on tht pad help me please. my emailid is harikaharikrishna6@gmail.com and im not gtng any compile time errors

    ReplyDelete
  18. Thnx dude..This made my day

    ReplyDelete
  19. great man.keep posting

    ReplyDelete
    Replies
    1. Thank you! We're open to suggestions for future tutorials.

      Delete
  20. This comment has been removed by the author.

    ReplyDelete
  21. i am getting an error saying to remove onclick() bec of multiple marks..
    please help me...

    ReplyDelete
  22. hey man if i click C button it shows "=undefined"
    what is the prb?
    operation working perfect but thi =undefinied is what ?

    ReplyDelete
  23. when i copy that code of calculator
    my calculator is made very esayly

    ReplyDelete
  24. i have no error in program but when i run there is show an eror msg tha "the application calculator has stop unexpectedly.please try again"..is there something missing..?????? may be in string.xml or androidmanifest.xml..??

    ReplyDelete
  25. I too am able to compile with no errors, buttons work great, but no numbers or values of the buttons show. Can someone please help me out? Jake.Koll21@gmail.com. Thank you.

    ReplyDelete
  26. The webView doesn't display any text.

    I don't know why , tried coloring text & all that color stuff.

    But, nope it doesn't work.

    While, I loved the code.

    I am eager to add it to my calc.

    Also, can you tell me adding wolfram API for integration.

    Thanks in advance.

    My email ID : akshaychordiya2@gmail.com

    ReplyDelete
  27. how can i get the result displayed in the webview. i need it to store in a string in order to use it.. plz ans...

    ReplyDelete
  28. how to resolved the =undefined when i click the "b button" and "c button" i think it must clear the webview? please help me email me at jefesanes@yahoo.com

    ReplyDelete
  29. I copied the Final Code 1to1 just to understand it first. However nothing is happening. The App loads in the VM but my button pushes aren't being captured by the OnClickListener :(
    Am I missing something?

    ReplyDelete
  30. I implemented this code in my app and Ive also read that numbers aren't showing up for some people.
    I have both both a physical DroidX, code works perfectly, and a Asus TF101 Tablet, which shows the calculator but does not show number input. I am trying to narrow down what the issue is but maybe this info will help someone do it faster than me. I am guessing incompatibility with versions?
    DroidX 2.3.4
    TF101 4.0.3

    ReplyDelete
  31. can any one explain why not webview displaying any numbers please??

    ReplyDelete
  32. i guess this might be a solution...

    replace:
    mWebView.loadData(builder.toString(), "application/xhtml", "UTF-8");

    with:
    mWebView.loadData(builder.toString(), "text/html", null);

    i know that UTF-8 is correct encoding, but for me second-one works..

    Regards,
    HBK

    ReplyDelete
    Replies
    1. Didn't work first,
      with this change it diplays correctly on my tf300t

      Delete
    2. right.you change text/html to text/xml.

      Delete
    3. Hi! Thanks for this! its works for me :D

      Delete
  33. I also cannot see the text in web view, just wanted to know if there is any plugin or some other stuff I need to download. My email is sheilsarda@yahoo.com. By the way, very nice step by step tutorials.

    ReplyDelete
  34. i need to create calculator of laos version so would help me

    ReplyDelete
  35. i have fix tool of boss.dont show any text when you are click.

    mWebView.loadData(builder.toString(), "application/xhtml", "UTF-8");

    replace by :

    webview.loadData(builder.toString(), "application/xml", "UTF-8");

    ReplyDelete
  36. so i have code actuarly is running very good.
    end the last ,thank you boss.so boss have help you
    trust that i will be success

    ReplyDelete
  37. When I press "C" it show's undefined message!

    What should be add to correct this one?

    ReplyDelete
  38. How do you make the calculator to occupy the whole screen?

    ReplyDelete
  39. Thank you, it is very usefull app! also thank you Anonymous for giving that code

    mWebView.loadData(builder.toString(), "text/html", null);

    it works for me:)

    ReplyDelete
  40. The Ce undefined problem can be solved by adding a flag value to switch case in public void onClick(View v) {
    switch (v.getId()) {
    case R.id.but_del:
    if(mMathString.length() > 0)
    mMathString.deleteCharAt(mMathString.length()-1);
    break;
    case R.id.but_Clear:
    if(mMathString.length() > 0)
    mMathString.delete(0, mMathString.length());
    flag = 0;

    break;
    default:
    flag = 1;
    mMathString.append(((Button) v).getText());
    }
    and accordingly add mWebView.loadData(builder.toString(), "text/html", null);

    if(flag == 0)
    {
    mWebView.loadData("", "text/html",null);
    }

    ReplyDelete
  41. When I click the buttons a toast is displayed as "Downloading not supported" What should I do?
    Please Help me..
    my e-mail : vihangarajalingam7@gmail.com
    Thanks.

    ReplyDelete
  42. pls send full source code
    my e-mail : prakharc0887@gmail.com

    ReplyDelete
  43. unable to see the text displayed on the webtext. the code is working error free.
    please share the details
    sakshinarang57@gmail.com

    ReplyDelete
  44. thank U so much :) :) :) i find ur post most useful to me as it is simple n effective than other calculator source codes for android tq so much...
    im tryna make calculator app for android which uses custom buttons....
    but i have a problem... getText() is not working coz i didnt menntion android:text in xml...
    can u sugest me few solutions...

    Thanku so much for ur beautiful idea... :D

    ReplyDelete
  45. myemail id: avinashlegendkiller@gmail.com

    ReplyDelete
  46. This comment has been removed by the author.

    ReplyDelete
  47. i am new in android and have a question: how this program do the math part?

    ReplyDelete