编译环境介绍

编译器为:Android studio 3.1.2;
SDK API 27 Android 8.1(Oreo);
java version jdk-11.0.2; 

UI设计

界面采用网格布局,在界面设计区域设置一个6行4列的网格布局,第一行为显示数据的文本标签,第2行为清楚数据的按钮,第3~6行均划分为4列,共安排16个按钮,分别代表数字0、1、2...、9及加、减、乘、除、等号等符号.

具体布局代码如下

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:columnCount="4"
    android:rowCount="6"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/contentText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_columnSpan="4"
        android:layout_marginLeft="4px"
        android:gravity="left"
        android:text="0"
        android:textSize="50dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/bt1"
        android:layout_width="353dp"
        android:layout_height="wrap_content"
        android:layout_columnSpan="4"
        android:text="清除"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt2"
        android:layout_width="wrap_content"
        android:text="1"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt3"
        android:text="2"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt4"
        android:text="3"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt5"
        android:text="+"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt6"
        android:text="4"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt7"
        android:text="5"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt8"
        android:text="6"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt9"
        android:text="-"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt10"
        android:text="7"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt11"
        android:text="8"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt12"
        android:text="9"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt13"
        android:text="*"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt14"
        android:text="."
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt15"
        android:text="0"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt16"
        android:text="="
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt17"
        android:text="/"
        android:textSize="26sp" />
</GridLayout>

 Strings.xml

<resources>
    <string name="app_name">计算器</string>
    <string name="bt1">clear</string>
    <string name="bt2">1</string>
    <string name="bt3">2</string>
    <string name="bt4">3</string>
    <string name="bt5">+</string>
    <string name="bt6">4</string>
    <string name="bt7">5</string>
    <string name="bt8">6</string>
    <string name="bt9">-</string>
    <string name="bt10">7</string>
    <string name="bt11">8</string>
    <string name="bt12">9</string>
    <string name="bt13">*</string>
    <string name="bt14">.</string>
    <string name="bt15">0</string>
    <string name="bt16">=</string>
    <string name="bt17">/</string>
</resources>

 

逻辑设计

计算器的逻辑实现大致有两种方案:

        1、当计算器接收两个操作数和一个运算符后,计算器就会输出结果

        2、计算机可接收任意长的表达式,待用户输入"="后,按照运算符的优先级进行运算,输出结果.

第一种方案的逻辑易于理解和实现,第二种方案的逻辑较为复杂,需建立栈结构将中缀表达式转换为后缀表达式,同时要对表达式进行合法性检测.因此本文采用的是第一种方案. 

具体逻辑代码如下

MainActivity.java

package com.example.bang.computer;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;


public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private Button[] buttons=new Button[17];
    private int[] ids=new int[]{R.id.bt1,R.id.bt2,R.id.bt3,R.id.bt4,R.id.bt5,R.id.bt6,R.id.bt7,
            R.id.bt8,R.id.bt9,R.id.bt10,R.id.bt11,R.id.bt12,R.id.bt13,R.id.bt14,R.id.bt15,R.id.bt16,R.id.bt17
    };
    private TextView textView;
    private String expression="";
    //判断运算是否结束
    private boolean end=false;
    //判断是否存在小数点
    private boolean point=false;
    //判断是否存在符号
    private boolean operation=false;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for(int i=0;i<ids.length;i++){
            buttons[i]=(Button)findViewById(ids[i]);
            buttons[i].setOnClickListener(this);
        }
        textView=(TextView)findViewById(R.id.contentText);
    }

    //判断输入是否符合规范
    public void onClick(View view){
        //获取被点击按钮的id
        int id =view.getId();
        Button button =(Button)view.findViewById(id);
        String current= button.getText().toString();
        if(end){
            expression="";
            end=false;
            point=false;
            operation=false;
        }

        if(current.equals("清除")){
            expression="0";
            end=true;
            point=false;
            operation=false;
        }
        else if (current.equals("+")||current.equals("-")||current.equals("*")||current.equals("/")){
            if(!operation){
                //表达式为空,
                if(expression.isEmpty()){
                    //输入为正负号,添加进表达式,但不改变符号状态
                    if (current.equals("-") || current.equals("+")) {
                        expression += current;
                    }
                    //输入为乘除号, 不执行操作
                    if (current.equals("*") || current.equals("/")) {
                    }
                }
                // 表达式不为空,且表达式最后位是数字
                else if(expression.charAt(expression.length()-1)>='0'&&expression.charAt(expression.length()-1)<='9'){
                    expression+=current;
                    operation=true;
                }
                point=false;

            }
            else{ //已经存在运算符
                //表达式最后一位是数字
                if(expression.charAt(expression.length()-1)>='0'&&expression.charAt(expression.length()-1)<='9'){
                    double result= count();
                    if(result==Double.MAX_VALUE){
                        expression="错误";
                    }else{
                        //保留两位小数
                        result =(double)Math.round(result*100)/100;
                        expression=""+result;
                        expression+=current;
                        point=false;
                    }
                }
            }
        }
        else if(current.equals("=")){
            //存在符号,且表达式最后一位是数字
            if(operation&&expression.charAt(expression.length()-1)>='0'&&expression.charAt(expression.length()-1)<='9'){
                double result= count();
                if(result==Double.MAX_VALUE){
                    expression="错误";
                }else{
                    //保留两位小数
                    result =(double)Math.round(result*100)/100;
                    expression=""+result;
                    end=true;
                }
            }
        }
        else if(current.equals(".")){
            if(!point){
                //如果表达式为空 或者表达式最后位不是数字, 输入. 默认加上0
                if(expression.equals("")||(expression.charAt(expression.length()-1)<'0'||expression.charAt(expression.length()-1)>'9')){
                    expression+="0";
                }
                // 存在符号 同时表达式最后位不是数字
                else if(operation&& (expression.charAt(expression.length()-1)<'0'||expression.charAt(expression.length()-1)>'9')){
                    expression+="0";
                }
                expression+=current;
                point=true;
                }
            }
        else{ //此时为数字
            if(end){
                expression="";
            }
                expression+=current;
        }

        textView.setText(expression);
    }

    private double count(){
        double result=0;
        double num1,num2;
        String str1,str2;

        int operateIndex=0;
        char operate='0';
        for(int i=0;i<expression.length();i++){
            //找出表达式的运算符
            if(expression.charAt(i)=='+'||expression.charAt(i)=='-'||expression.charAt(i)=='*'||expression.charAt(i)=='/'){
                operateIndex=i;
                operate=expression.charAt(i);
            }
        }
        str1=expression.substring(0,operateIndex);
        str2=expression.substring(operateIndex+1,expression.length());

        num1=Double.parseDouble(str1);
        num2=Double.parseDouble(str2);

        if(operate=='+'){
            result=num1+num2;
        }
        else if(operate=='-'){
            result=num1-num2;
        }
        else if(operate=='*'){
            result=num1*num2;
        }
        else if(operate=='/'){
            if(num2==0){//返回最大值,作为判断错误的依据(待改进)
                return Double.MAX_VALUE;
            }
            else{
                result=num1/num2;
            }
        }
        return result;
    }
}

 

效果图

 

android 计算器 依赖 android计算器报告_xml

 

实验心得:

本次实验是我首个安卓项目,界面设计不够美观.同时逻辑实现较为粗糙.为了增强代码的健壮性,避免用户的非法输入导致程序崩溃,在检测表达式合法性中,加入了大量的判断,降低了代码的可读性,有较大的优化空间.虽然经过多次实验和修改,尚未发现漏洞,但仍有存在漏洞的可能.