一、实验目的

练习掌握 Android 软件开发的界面布局,事件编程等基本编程技术,设计制作一 Android 计算器软件。

二、实验内容

实现的计算器功能和界面可在实验开发由每位同学设计,以下功能和软件界供参考:
一个计算器的基本功能应有输入数据、加减乘除、浮点数运算、正余弦运算、清空结果、删除一位数据。
(1)数字以字符形式输入,在需要读出数据的时候直接调用 getText()函数即可。
(2)对于双目运算符,在检测到点击时,得到输入框里的数据 num1,输入框置空,并设置标志 op 标明是哪种运算。对于除法运算需要判断,除数是否为零并提醒。
(3)对于单目运算符,在检测到点击时,设置标志 or 标明是哪种运算。 (4)在清空时,需要将输入框置空。清除一位数据时,判断输入框中是否只有一个数据,如是,直接清空,如不是输入框中置前 n-1 位。
(5)在点击等于符号时,得到输入框里的数据 num2,根据前面设置的标志位,判断点击的是单目运算符还是双目运算符,若是单目运算符就将 num2 进行单目运算。若是双目运算,num2 不变。再进行 Result 运算。

三、实验要求

(1)每位同学独立设计软件功能、完成软件的开发与测试。
(2)每位同学独立完成实验报告(根据模板),并提交至网络课堂

该计算器分为两种模式,包括标准模式和科学计算
由于源码较多,只放出核心的科学计算部分
以下给出的代码主要是涉及事件的触发和全局的信息传递
说明:ScientificCalculator.java

package com.example.luozenglin.service;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.example.luozenglin.calculator.MainActivity;
import com.example.luozenglin.calculator.R;
import com.example.luozenglin.common.InputItem;
public class ScientificCalculator extends StandardCalculator {
    protected Button antiBtn;
    protected Button perCent;
    protected Button sinBtn;
    protected Button cosBtn;
    protected Button tanBtn;
    protected Button powerBtn;
    protected Button lgBtn;
    protected Button lnBtn;
    protected Button leftBraBtn;
    protected Button rightBraBtn;
    protected Button squareRootBtn;
    protected Button factorialBtn;
    protected Button reciprocalBtn;
    protected Button pIBtn;
    protected Button eBtn;
    public ScientificCalculator(Activity activity){
        super(activity);
    }
    @Override
    protected void init() {
        super.init();
        antiBtn = (Button) activity.findViewById(R.id.anti_btn);
        sinBtn = (Button) activity.findViewById(R.id.sin_btn);
        cosBtn  = (Button) activity.findViewById(R.id.cos_btn);
        tanBtn = (Button) activity.findViewById(R.id.tan_btn);
        powerBtn = (Button) activity.findViewById(R.id.power_btn);
        lgBtn = (Button) activity.findViewById(R.id.log_btn);
        lnBtn = (Button) activity.findViewById(R.id.ln_btn);
        leftBraBtn = (Button) activity.findViewById(R.id.leftBracket_btn);
        rightBraBtn = (Button) activity.findViewById(R.id.rightBracket_btn);
        squareRootBtn = (Button) activity.findViewById(R.id.squareRoot_btn);
        factorialBtn = (Button) activity.findViewById(R.id.factorial_btn);
        reciprocalBtn = (Button) activity.findViewById(R.id.reciprocal_btn);
        pIBtn = (Button) activity.findViewById(R.id.PI_btn);
        eBtn = (Button) activity.findViewById(R.id.e_btn);
        perCent = (Button) activity.findViewById(R.id.perCent_btn);
        map.put(sinBtn,activity.getString(R.string.sin));
        map.put(cosBtn,activity.getString(R.string.cos));
        map.put(tanBtn,activity.getString(R.string.tan));
        map.put(powerBtn,activity.getString(R.string.power));
        map.put(perCent, "%");
        map.put(lgBtn,activity.getString(R.string.log));
        map.put(lnBtn,activity.getString(R.string.ln));
        map.put(leftBraBtn,activity.getString(R.string.leftBra));
        map.put(rightBraBtn,activity.getString(R.string.rightBra));
        map.put(squareRootBtn,activity.getString(R.string.squareRoot));
        map.put(factorialBtn,activity.getString(R.string.factorial));
        map.put(reciprocalBtn,activity.getString(R.string.reciprocal));
        map.put(pIBtn,activity.getString(R.string.PI));
        map.put(eBtn,"e");
    }
    @Override
    protected void setOnClickListener() {
        super.setOnClickListener();
        powerBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                inputOpe(v);
            }
        });
        perCent.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                inputOpeOpe(v);
            }
        });
        antiBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                transTrigon();
            }
        });
        sinBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                inputNumOpe(v);
            }
        });
        cosBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                inputNumOpe(v);
            }
        });
        tanBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                inputNumOpe(v);
            }
        });
        lgBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                inputNumOpe(v);
            }
        });
        lnBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                inputNumOpe(v);
            }
        });
        squareRootBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                inputNumOpe(v);
            }
        });
        leftBraBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                inputLeftBra();
            }
        });
        rightBraBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                inputRightBra();
            }
        });
        factorialBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                inputOpeOpe(v);
            }
        });
        reciprocalBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                inputOpeOpe(v);
            }
        });
        pIBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                inputOpeNum(v);
            }
        });
        eBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                inputOpeNum(v);
            }
        });
    }
    @Override
    protected void transform() {
        Intent intent = new Intent(activity, MainActivity.class);
        activity.startActivity(intent);
    }
    protected void transTrigon(){
        if(antiBtn.getText().equals(activity.getString(R.string.radian))){
            antiBtn.setText(activity.getString(R.string.deg));
        }else if(antiBtn.getText().equals(activity.getString(R.string.deg))){
            antiBtn.setText(activity.getString(R.string.radian));
        }
    }
    protected void inputTrigonometricFunction(View view){
    }
    protected void inputNumOpe(View view){
        if( currentStatus == CurrentStatus.END){
            initEndStatus();
        }
        if(isInitInputList()){
            subInputListAndInputTV();
        } else if(getLastInputItem().getType()== InputItem.TYPE.NUM ||
                getLastInputItem().getType()== InputItem.TYPE.RIGHT_BRACKET){
            inputOpe(mulBtn);
        }
        inputList.add(new InputItem(map.get(view), InputItem.TYPE.NUM_OPE));
        addTV(view);
        inputLeftBra();
        Log.i(activity.getClass().getSimpleName(),"add ope: "+map.get(view)+
                "\ninputList: "+getInputListValues());
    }
    protected void inputOpeOpe(View view) {
        if (getLastInputItem().getType()!= InputItem.TYPE.NUM                      //OPT_OPT前必须是数字或右括号
                && getLastInputItem().getType()!= InputItem.TYPE.RIGHT_BRACKET) {
            Log.i(activity.getClass().getSimpleName(),"Last input is "+
                    getLastInputItem().getValue()+", can not add "+map.get(view));
            return;
        }
        inputList.add(new InputItem(map.get(view), InputItem.TYPE.OPE_OPE));
        addTV(view);
        Log.i(activity.getClass().getSimpleName(),"inputList:  "+getInputListValues());
    }
    protected void inputOpeNum(View view){
        if( currentStatus == CurrentStatus.END){
            initEndStatus();
        }
        if(isInitInputList()){
            subInputListAndInputTV();
        }else if(getLastInputItem().getType()== InputItem.TYPE.NUM ||
                getLastInputItem().getType()== InputItem.TYPE.RIGHT_BRACKET){
            inputOpe(mulBtn);
        }
        inputList.add(new InputItem(map.get(view), InputItem.TYPE.OPE_NUM));
        addTV(view);
        Log.i(activity.getClass().getSimpleName(),"add ope: "+map.get(view)+
                "\ninputList: "+getInputListValues());
    }
    protected void inputLeftBra(){
        if( currentStatus == CurrentStatus.END){
            initEndStatus();
        }
        if(isInitInputList()){
            subInputListAndInputTV();
        }else if(getLastInputItem().getType()!= InputItem.TYPE.OPE && getLastInputItem().getType()!= InputItem.TYPE.NUM_OPE
                && getLastInputItem().getType()!= InputItem.TYPE.LEFT_BRACKET){
            inputOpe(mulBtn);
        }
        inputList.add(new InputItem(map.get(leftBraBtn), InputItem.TYPE.LEFT_BRACKET));
        addTV(leftBraBtn);
        Log.i(activity.getClass().getSimpleName(),"add ope: "+map.get(leftBraBtn)+
                "\ninputList: "+getInputListValues());
    }
    protected void inputRightBra(){
        if(getLastInputItem().getType()== InputItem.TYPE.OPE){
            subInputListAndInputTV();
        }
        inputList.add(new InputItem(map.get(rightBraBtn), InputItem.TYPE.RIGHT_BRACKET));
        addTV(rightBraBtn);
        Log.i(activity.getClass().getSimpleName(),"add ope: "+map.get(rightBraBtn)+
                "\ninputList: "+getInputListValues());
    }
}

以下截图为计算器的布局,分为标准和高级

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

Android Studio 的坑

Error:Protocol family unavailable该错误很多地方都是说防火墙的问题其实不然。参考http://bbs.csdn.net/topics/391951751?page=1 在环境变量中增加新的变量 _JAVA_OPTIONS 其变量值为-Djava.net.preferIPv4Stack=true ,之后重启Android studio
Error running app: Instant Run requires 'Tools | Android | Enable ADB integration' to be enabled.解决方案:菜单栏,Tools -> Adnroid -> enable ADB integration
Error:(1, 0) Cause: com/android/build/gradle/LibraryPlugin : Unsupported major.minor version 52.0这个错误的原因是在 工程的build.gradle文件中的gradle 工具配置使用了gradle:将它classpath ‘com.Android.tools.build:gradle:’
替换为固定版本的gradle。classpath “com.android.tools.build:gradle:2.1.0”
Android Studio 错误: 非法字符: '\ufeff' 解决方案|错误: 需要class, interface或enum解决方法:手动将UTF-8+BOM编码的文件转为普通的UTF-8文件。用EdItPlus打开.java文件依次:文档》文本编辑》转换文本编码》选择UTF-8编码即可
项目导入到AS中出现以下问题:Error:Execution failed for task:app:transformResourcesWithMergeJavaResForDebug' com.android.bui解决方法:在build.grade中添加以下代码:
android{
packagingOptions {
exclude 'META-INF/DEPENDENCIES.txt’exclude
'META-INF/NOTICE’exclude ‘META-INF/NOTICE.txt’
exclude 'META-INF/LICENSE’exclude ‘META-INF/LICENSE.txt’}}

心得体会

把一些常用的工具类或业务流程代码进行归类整理,加入自己的代码库。如加解密、拍照、裁剪图片、获取系统所有图片的路径、自定义的控件或动画以及其其他他一些常用的工具类等。归档有助于提高开发效率,在遇到新项目的时候随手即可引入使用。如果你想要更好的维护自己的代码库,可以把这个私人代码库加上详细文档给开源出去。 这样能够吸引更多开发者来使用这些代码,也可以获得相应的bug反馈,以便于着手定位修复问题,增强这个仓库代码的稳定性。

Activity的四大启动模式:

• standard:标准模式,每次都会在活动栈中生成一个新的Activity实例。通常我们使用的活动都是标准模式。
• singleTop:栈顶复用,如果Activity实例已经存在栈顶,那么就不会在活动栈中创建新的实例。比较常见的场景就是给通知跳转的Activity设置,因为你肯定不想前台Activity已经是该Activity的情况下,点击通知,又给你再创建一个同样的Activity。
• singleTask:栈内复用,如果Activity实例在当前栈中已经存在,就会将当前Activity实例上面的其他Activity实例都移除栈。常见于跳转到主界面。
• singleInstance:单实例模式,创建一个新的任务栈,这个活动实例独自处在这个活动栈中。

Android消息机制中的四大概念:

• ThreadLocal:当前线程存储的数据仅能从当前线程取出。
• MessageQueue:具有时间优先级的消息队列。
• Looper:轮询消息队列,看是否有新的消息到来。
• Handler:具体处理逻辑的地方。
过程:

  1. 准备工作:创建Handler,如果是在子线程中创建,还需要调用Looper#prepare(),在Handler的构造函数中,会绑定其中的Looper和MessageQueue。
  2. 发送消息:创建消息,使用Handler发送。
  3. 进入MessageQueue:因为Handler中绑定着消息队列,所以Message很自然的被放进消息队列。
  4. Looper轮询消息队列:Looper是一个死循环,一直观察有没有新的消息到来,之后从Message取出绑定的Handler,最后调用Handler中的处理逻辑,这一切都发生在Looper循环的线程,这也是Handler能够在指定线程处理任务的原因。

相关资源

依赖库与SDK

必选的库:
gradle-retrolambda——Android的lambda表达式插件
fresco——Android最屌图片加载库
material-dialogs ——Material Dialog向下兼容库
material-ripple——Ripple向下兼容库
fastjson——最快JSON解析
butterknife——View注解库和配套插件android-butterknife-zelezny
ActiveAndroid——数据库注解库。
RxAndroid——Rx函数响应式编程中文文档
retrofit,okhttp,sqlbrite,okio——Square家的精品多啊
compile ‘com.android.support:design:23.0.1’——谷歌Material Design控件库
下面安利几个自己写的库,如果有什么建议欢迎交流:
Utils——Android各种小功能集合
RollViewPager——自动轮播使用方便的ViewPager
EasyRecyclerView——支持下拉上拉刷新等功能全面的RecyclerView
SwipeBackHelper——Activity滑动关闭支持库,能达到微信效果
尝试了很多,这几个是现在常用的。
融云——即时通讯
友盟——数据统计,推送,意见反馈,自动更新,第三方分享及登录,社区
七牛——云存储
Mob——短信验证
Bmob——做后台不求人

完整代码见我发的资源

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐