分类目录归档:安豆计算器

音乐播放器 第3节 获取音乐信息

第3节 获取音乐信息

在“视频播放器”的开发过程当中,我们已经学会了如何获取视频文件的信息:

  1. 定义一个视频信息的数据结构VideoItem
  2. 自定义一个AnsycTask,在它的工作线程中查询视频;
  3. 在工作线程中,访问MediaProvider,获取视频数据;
  4. 将视频数据显示到自定义的列表项中;

这里列举音乐文件,也采用类似的方式:

  1. 定义一个音乐信息的数据结构MusicItem
  2. 自定义一个AnsycTask,在它的工作线程中查询音乐;
  3. 在工作线程中,访问MediaProvider,获取音乐数据;
  4. 将音乐数据显示到自定义的列表项中;

3.1 音乐数据的获取原理

与获取视频信息的方式几乎一样,获取音乐信息也是通过系统自带的MediaProviderMediaProvider里面存储了所有的多媒体数据信息,不仅有视频,还包括各种音频文件。

  1. Media Provider发出查询请求的地址-uri,它就像访问网站时,要输入的网址一样。系统提供了两个位置的uri,一个是指向内部存储的uri,一个是指向外部存储的uri。我们要查询的音乐文件都是存放在外部存储地址上的;

  2. 确定要请求的视频文件信息。在视频列表中,我们需要展示视频的标题、创建时间,还需要播放它时使用的文件所在地址。这些信息在Media Provider中都对应着查询它们使用的字段名称;

  3. 确定查询的条件。我们之前假设过:只关心那些包含了music关键字的目录。因此我们要确定的只是查询到的文件路径中,包含有music这个字段。

    这个条件参数的写法就和SQL数据库语言的语法一样。这里我们不打算讲SQL语法,只要知道在我们这个例子中这样使用就好了;

  4. 设定查询结果的排序方式,使用默认的排序方式就可以了,

  5. 获取ContentResolver对象,让它使用前面的参数向Media Provider发起查询请求;查询的结果存放在Cursor--指标当中;

  6. 遍历Cursor,得到它指向的每一条查询到的信息;当Cursor指向某条数据的时候,我们就获取它携带的每个字段的值;

    每首音乐都有一个全局唯一的URI地址,操作某首具体的音乐就可以通过这个地址来完成。而id就是用来获取该音乐的URI地址的,将id与音频的URI地址组合一下就能得到特定某首音乐的URI地址,它的形式就像content://media/external/audio/media/20310

    获取音乐的封面,

    1. 需要知道它所属的专辑idalbumId

    2. 根据这个id与专辑封面的uri(content://media/external/audio/albumart)组合,得到专辑所在的Uri,它的形式就像content://media/external/audio/albumart/4

    3. 通过下面的方式,创建出封面图片,

      这是一个很多模块都可能用到的功能,我们将它做成一个函数,放到Utils.java文件中,便于其它模块使用,

  7. 存放获取的视频文件信息,创建一个MusicItem类

    创建封面图片的方法上面已经介绍过了。一开始,我们可以暂时不用创建出封面图片,只保留albumId,在需要的时候再去创建出封面,一旦创建出封面图片,就把它保存在thumb这个成员变量当中。

    创建一个MusicItem

  8. Cursor使用完了之后要把它关闭掉,


整理一下前面的各个步骤,获取外部存储上music目录中所有音频文件的方式如下,

最后一点千万不要忘记,要在应用的AndroidManifest.xml文件中,添加读取外部存储器的权限,

3.2 在工作线程中获取音乐信息

主线程中不能做耗费时间到事情,如果要进行耗时的操作需要开启一个工作线程,把耗时操作交给工作线程处理。查询音乐的信息就是一个耗时的操作(准确的说是不知道什么时候能查询完,如果设备上的音乐文件很少,那么也许很快就完成了,但如果音乐文件很多,也会会花上很多很多时间)。

为此,我们还是采用“视频播放器”中的设计,创建一个叫做MusicUpdateTaskAsyncTask,在它的doInBackground()方法中去进行查询操作。

AsyncTask的原理和用法,我们已经在“视频播放器”的部分详细讲过了,这里就假设大家对它的使用已经比较熟悉了。

与“视频播放器”的设计不同,这里我们简化了设计,只用到了AsyncTaskonProgressUpdate()方法和doInBackground()方法。

另外,在列表加载的过程中,也没有让用户手动选择停止加载列表的功能。如果你觉得这个功能很重要,可以模仿“视频播放器”的设计,在这里添加上。我们在这里取消了这个设计,主要的目的只是为了让大家快速的梳理一下曾经具有的开发经验,节省时间,从而尽快的将我们带入带新的开发知识上去。

在使用MusicUpdateTask的时候,在主界面所在的MusicListActivity创建和销毁时,分别启动和取消MusicUpdateTask的运行,

3.3 音乐列表展示

我们给音乐列表设计了如下的界面,

我们已经知道了如何实现一个自定义的列表,

  1. 为每一条列表项定义它的外貌-布局文件;
  2. 自定义一个Adapter,将要展示的数据放入其中;
  3. 在主界面的布局文件中放入ListView控件,将Adapter设置到ListView中,让ListView展示所有数据;

3.3.1 音乐项的界面布局

每个数据项,要展示音乐的封面、名称、播放时长,

为此,我们给它定义个布局music_item.xml,将界面区域这样分割:

  1. ImageView用来放置歌曲封面,给它指定一个图片的大小,150dp x 100dp;背景颜色采用主题属性colorPrimary的颜色;

  2. 封面的id设置成music_thumb,音乐名称的id设置成music_title,播放时长的id设置成music_duration

整个布局方式如下,

3.3.2 自定义Adapter

这里自定义MusicItemAdapter的方法,与自定义VideoItemAdapter的方法几乎一模一样,只是,

  1. Adapter保存的数据类型不同,从VideoItem变成了MusicItem

  2. 时间格式我们将显示成32:21这种形式,所以可以采用这样的实现,

    这是一个很多模块都可能用到的功能,我们将它做成一个函数,放到Utils.java文件中,便于其它模块使用,

MusicItemAdapter的实现如下,

3.3.3 通过ListView使用Adapter

有了Adapter和数据,就要把它们结合起来,放到ListView中,以列表的形式展示出来。

  1. MusicListActivity的布局activity_music_list.xml当中,加入列表,

  2. onCreate()中,创建Adapter,并设置给ListView

  3. MusicUpdateTask获取的音乐数据放入到ListView当中,需要完善MusicUpdateTask()方法,

因为列表中显示封面的时候,创建了不少图片,在Activity退出的时候,我们要手动的回收这些图片占用的空间,


好了,当我们运行应用的时候,就会看到设备上music目录下的音乐都被显示出来了。

3.4 测试音乐播放

音乐列表准备好了,我们来试试播放音乐吧。
前面我们介绍了如何使用MediaPlayer来播放音乐,这里我们让用户点击音乐列表上的特定音乐后,就开始播放它,

  1. 为音乐列表的音乐项设置点击的监听,

  2. 在点击响应处,添加播放音乐的代码,

    每次点击前都调用一次mMusicPlayer.reset(),可以清除以前播放器的状态。

这样一来,用户点击音乐的时候,就可以播放制定的音乐了。

**注意,这里只是为了让我们直观的感受到音乐列表的完成,并能够播放音乐,但是程序的框架并没有按照我们之前设计那样,所以只能算是效果的验证。

在后面的章节中,我们将修改这里的设计,按照正确的设计框架来实现音乐播放。**

所以最后,让我们清除这段测试播放音乐用的代码吧。

/**************************************************************************/
* 版权声明
* 本教程只在CSDN安豆网发布,其他网站出现本教程均属侵权。
/
**************************************************************************/

安豆计算器 后记

后记

经过前面的学习和实践,我们已经开发出了一款简单的计算器应用,对安卓应用开发有了整体的认识。

安卓开发的学习还有更多有趣好玩的道路需要走,下面给出一些学习的建议和方法:

  1. 安豆网上有配套的《大话安卓开发》,会将这里没有深入展开的内容,按照知识体系进行进一步的讲解。当我们对安卓的开发有了大概的认识后,可以去看看成体系的介绍和学习,让我们对开发的认识和理解更进一步;
  2. 对于困惑或者根本没有任何头绪的问题,去搜索引擎上尝试寻找答案,也许别人也遇到过类似的问题,站在前人的肩上,总会节约不少时间;
  3. 在时间允许的情况下,多做测试程序,把从书上、网上看到的内容消化成自己知识体系的一部分;
  4. 常去安卓开发的官网看看,上面有很多关于安卓应用开发的第一首资料;
  5. 对网上看到的有矛盾的资料,去官网查看权威的API文档;
  6. 乐于与别人分享自己在学习或者实践中遇到的问题和解决方法,与大家共同进步;

安豆计算器 第9节 动画效果

第9节 动画效果

当用户点击了以后,为了让结果区域的显示和表达式区域的清空显得很优雅,我们可以为它们添加淡如淡出的效果:让结果区域的文字淡入,让表达式区域的文字淡出。

这种效果可以使用动画实现。

安卓系统的动画可以分成,

  1. 逐帧动画:就像电影胶片那样,通过连续放映一张一张差距不大的图片实现动画效果;
  2. 属性动画:一点点改变控件的某个属性值,从而产生动画的视觉效果;
  3. 渐变动画:产生控件的透明效果 平移效果 缩放效果或者旋转效果

我们准备加入的文字淡入淡出效果,就是渐变动画的透明效果

9.1 定义动画

  1. 项目浏览框,找到res目录,点击右键,选择new->android resource file;

  2. 在对应栏位按照下图填写,创建一个淡入动画;

  3. 打开刚创建好的xml文件,定义淡入动画;android:fromAlpha指定动画开始时,动画对象的透明度;android:toAlpha指定动画结束时,动画对象的透明度;android:duration指定了动画持续的时间,单位是毫秒;android:interpolator指定了动画显示过程中变化的速度;

  4. 根据前面的操作,继续创建一个淡出动画,叫做fade_out

9.2 使用动画

9.2.1 使用淡入效果

  1. 在源码中,使用AnimationUtils.loadAnimation()函数加载我们定义的动画;
  2. 为要使用动画的对象通过startAnimation()方法设置对象;

9.2.2 使用淡出效果

如果使用9.2.1中的方式,直接对对象使用淡出效果,会发现对象一开始就消失不见了,而不是逐步消失的。因为在动画开始之前,我们就已经通过formula.setText("");将表达式区域设置成空了。因此,需要在淡出动画完成后,再把表达式区域设置成空。

  1. 在源码中,使用AnimationUtils.loadAnimation()函数加载我们定义的动画;
  2. 为动画添加监听,掌握动画进行的过程;
  3. 在动画结束时,将表达式区域设置成空;

至此,整个动画的添加就完成了,运行程序,开始计算操作,可以看到动画效果了。

安豆计算器 第8节 关于界面

第8节 关于界面

现在我们开始为应用增加一个自我介绍,自我介绍也是一个Activity,它将从应用右上方的菜单栏启动。

8.1 菜单的添加

应用标题栏的区域,叫做Actionbar。这里用来显示应用的名字,提供应用的各种操作菜单。我们就要在这里添加一个关于菜单。

  1. 项目浏览框,找到res目录,点击右键,选择new->android resource file;

  2. 在对应栏位按照下图填写;

  3. 在新创建的xml文件中加入菜单项,showAsAction属性表示菜单是否直接显示出来,如果给他指定never,那么它将被折叠到右上角的三个点当中;title属性用来指定菜单项要显示的文字,我们这里采用字符串引用的方式,将菜单栏文字设置成About

  4. MainActivity.java的源码中,把菜单项添加到Actionbar上,

  5. MainActivity.java的源码中,添加对菜单项点击对响应,

至此,菜单功能就添加好了,等我们创建好了“关于”界面的Activity之后,再来修改菜单点击的响应,让它启动“关于”界面。

8.2 Activity的添加

8.2.1 创建Activity

  1. 项目浏览窗口,找到程序源码所在的包,点击右键,选择new->Activity->Gallery...

  2. 选择Empty Activity

  3. 按下面表格的内容,设置好Activity和布局文件的名字,

这样,Activity相关的代码和布局文件就创建完成了。
在创建的过程中,应用的AndroidManifest.xml也被自动加上了以下的内容,对新添加的Activity进行了注册,否则,启动这个Activity的时候,系统会报错。

8.2.2 创建Activity布局

在布局中我们添加上版本信息和用户信息。

  1. 修改res\layout\activity_about.xml文件,使用TextView来显示用户和版本信息;背景颜色使用之前定义的#FF4B5459

  2. 关于界面显示的文字,定义一种style,然后为TextView指定这种style,

  3. AboutActivity.java中的onCreate()函数,使用PackageManager获取安装的应用信息,进而获取版本号;代码如下,

  4. res\values\strings.xml中,添加格式化字符串,

  5. 使用格式化字符串,String.format()可以将%s替换成我们希望被代替的字符串,

8.2.3 启动Activity

最后在菜单项的响应函数里面,把刚创建好的Activity启动起来。
启动另外一个Activity可以通过Activity提供的startActivity()方法;
这里需要首先创建一个Intent,给intent填入要启动的Activity的类名,

在设备上将程序运行起来,就可以看到“关于”界面成功的添加并显示了。

安豆计算器 第7节 横屏界面

第7节 横屏界面

很多应用都会根据设备的横竖屏状态,呈现不同的界面。为的是在不同屏幕长宽的情况下,合理的利用屏幕空间,让用户获得体验上的最佳。
这一节,我们将给计算器添加横屏的布局界面。

7.1 修改方案

添加横屏布局的原理很简单,

  1. res目录下增加layout-land目录;
  2. 在此目录下增加一个同样名字为activity_main.xml的布局文件;
  3. 将设备横屏时希望的布局效果在activity_main.xml中实现;
  4. 重新在设备上运行程序;
  5. 当设备从竖屏转成横屏时,onCreate()函数会被重新调用,setContentView()函数此时加载的布局文件,就是res\layout-land\activity_main.xml

7.2 调整竖屏结构

通过观察我们可以发现横屏界面和竖屏界面在很多地方都是有相似的。图中相同的色块都比较相似,如果能提取出来重复使用就好了。

为了使横竖界面的布局模块能够抽取出来,保持一致。我们首先要对竖屏界面的布局方式作出修改,让它变成像色块分区那样的结构。这里只需要调整键盘区域,修改activity_main.xml文件,让其布局结构按如下方案修改:

7.3 用标签提取公共布局

Android SDK为我们提供了两种标签,方便开发者在布局文件中重复利用相同的布局。

7.3.1 模块化显示区域

  1. res\layout目录下创建display_area.xml;
  2. 将显示区域的布局放到新建的xml文件当中,最外层使用merge标签;

  3. 替换res\layout\activity_main.xml中显示区域的布局为标签;标签的layout属性用来制定要包含的其他布局,这里要使用@layout/进行引用。

7.3.2 模块化数字按键区域-0~9.

  1. res\layout目录下创建digital_btn_area.xml;
  2. TableLayout中的布局放到新建的xml文件当中,最外层使用merge标签;

  3. 替换res\layout\activity_main.xml中的对应区域的布局为标签;

7.3.3 模块化浅色符号按键区域-C DEL

  1. res\layout目录下创建symbol_light_btn_area.xml;
  2. 将浅色符号区域LinearLayout中的布局放到新建的xml文件当中,最外层使用merge标签;
  3. 需要注意的是,这里要把android:layout_widthandroid:layout_height都设置成match_parent,为的是在横屏的时候,这部分按钮也可以被平均分配;

  4. res\layout\activity_main.xml中的对应区域,使用标签;

7.3.4 模块化深色符号按键区域-

  1. res\layout目录下创建symbol_dark_btn_area.xml;
  2. 将深色符号区域LinearLayout中的布局放到新建的xml文件当中,最外层使用merge标签;

  3. res\layout\activity_main.xml中的对应区域,使用标签;

7.4 创建横屏布局

按照横屏的设计创建横屏布局文件。

  1. 项目浏览框,找到res目录,点击右键,选择new->android resource file;

  2. 在对应栏位按照下图填写;

  3. 布局方向,选择landscape;这样Android Studio就会在在res目录下增加layout-land目录;并在此目录下增加一个名字为activity_main.xml的布局文件;

  4. 修改新创建的布局文件为,

  5. 重新运行程序到设备上,并选择设备,就会发现计算器的界面会根据设备横竖状态的不同而自己切换了。

7.5 数据保存

虽然计算器的横竖屏会自动切换界面了,但是我们会发现一个问题:当在竖屏界面输入计算表达式以后,旋转设备,表达式区域会被清空。

所以需要我们增加一个功能,让设备旋转的时候,数据不会被清除掉。

7.5.1 开发框架的优势

Activity由Android SDK开发框架提供给我们使用。它帮助我们完成了很多应用界面启动后需要进行的操作。当我们需要在这些操作中添加自己希望的逻辑时,就可以通过继承覆盖这些方法,覆盖时加上自己的代码,例如Activity的:

这也就是使用框架进行开发的优势。

7.5.2 调用时机

在Activity众多的方法当中,onSaveInstanceState()onRestoreInstanceState()提供了一个Activity被系统自动销毁时,进行处理的机会。

Activity一般是在用户点击返回按钮后被销毁的,但是有的时候也会被操作系统自动销毁,

  1. 系统资源不足时,操作系统会销毁在后台的Activity(隐藏起来不可见的Activity,虽然可见但是没有和用户做交互的Activity);
  2. 当系统的属性发生了变化,需要重新创建这个Activity时,设备的横竖屏状态变化,就满足这个条件;

onSaveInstanceState()会在Activity被切换到后台的时候被调用,我们就应该在这里添加上保存数据的逻辑。

如果Activity被系统自动销毁,而下一次系统又要把这个Activity切换到前台,系统就会自动重新创建这个Activity,此时才会触发onRestoreInstanceState()被调用,在这个时候,我们就可以添加恢复数据的逻辑了。

7.5.3 保存和取出方式

保存数据时,

  1. 获取计算表达式和结果的内容;
  2. 将表达式和结果的内容存放到系统提供的Bundle当中;

恢复数据时,

  1. 从系统提供的Bundle中,取出之前保存的数据;
  2. 将内容重新设置到计算表达式区域和计算结果区域;

至此,计算器横竖屏旋转时代功能就添加完毕了。

安豆计算器 第6节 优化资源使用

第6节 优化资源使用

字符串、颜色以及各种尺寸相关的值都属于程序的资源。
我们前面都是直接使用的这些资源,例如,

其实这些资源可以分门别类的放到单独的位置定义,然后通过@引用的方式进行使用。

6.1 优化颜色

颜色的定义和使用,

  1. 颜色应该定义到res\values\colors.xml当中,

  2. 在需要使用它的地方采用引用的方式,@color/

6.2 优化尺寸

尺寸的定义和使用,

  1. 尺寸应该定义到res\values\dimens.xml当中,

  2. 在需要使用它的地方采用引用的方式,@dimen/

6.3 优化字符串

字符串的定义和使用,字符串应该定义到res\values\strings.xml当中,

6.3.1 xml使用字符串

在布局文件中使用字符串,应该采用引用的方式,@string/

6.3.2 代码使用字符串

在代码中使用字符串,应该采用如下方式,

其中context是一个应用到上下文环境。对一个Activity来说,就是Activity自身MainActivity.this

将代码中所有使用资源的地方,都按照前面介绍的方式进行改造。以后在修改代码的时候,就不会牵一发而动全身了,只需要修改一处,就能够把所有需要修改的地方都修改到了。

6.3.3 多国语言支持

安卓系统,支持多国语言,现在我们将添加对中文支持。

  1. res目录下,点击右键,启动创建android resource的向导;

  2. File name栏,输入strings.xml,再选中下方的locale,添加到右边;

  3. 选中zh,代表中文;

  4. 在创建出来的中文的res\values-zh\strings.xml文件中,仿照res\values\strings.xml的内容,添加中文语言;

这里的app_name,在AndroidManifest.xml文件中被使用,里面使用了android:label属性,指定这个应用的名称。

至此,中文语言的支持,添加完成。在设备上运行程序后,会看到现在“计算器”应用到名称已经变成中文的计算器了。

6.4 style优化

已经定义的Style中,有很多相同的部分,可以将它们提取出来共同使用。
style可以继承自另一个style,

  1. 将共同使用的部分定义到BaseBtnStyle当中,

  2. 各种风格的Button继承BaseBtnStyle,使用parent=关键字;然后再加入不同的元素,

现在资源使用方式的优化就完成了。

安豆计算器 第5节 界面美化

第5节 界面美化

这一节,我们将对粗糙的计算器界面进行美化,最后让它的效果如下,

5.1 整体背景色

给整个背景调整一个背景颜色,让它变得美观。

  1. 在布局文件activity_main.xml中,给整个界面增加一个背景颜色#FF4B5459,对界面的父布局LinearLayout使用android:background属性设置;
  2. 这里的颜色是采用AARRGGBB的形式进行定义的,AA表示透明度,RR代表红色,GG代表绿色,BB代表蓝色;

5.2 美化显示区域

开始调整显示区域。

5.2.1 添加显示区域分隔栏

结果显示区域和表达式显示区域混在一起,不易分辨,需要把它们分开;

  1. 它们表达式区域和结果区域之间,增加一条间隔线,高度设置为5dp
  2. 间隔线的颜色为#FF5C6265

5.2.2 修改字体和排列

  1. 显示区域的字体颜色通过android:textColor属性设置成白色#FFFFFFFF
  2. 字体大小通过android:textSize属性设置成45sp
  3. 通过android:gravity属性让文字位于左边居中显示;
  4. 显示区域的页边距通过android:padding属性设置成5dp

5.3 美化键盘

接下来开始美化键盘。

5.3.1 字体大小和颜色修改

修改Button的字体大小和字体颜色,与修改TextView的字体大小和字体颜色完全一样,

  1. android:textColor设置文字颜色为黑色#FF000000
  2. android:textSize设置文字大小为35sp

5.3.2 增加按钮效果

下面开始修改Button的按键背景效果,我们的键盘有3种效果:

  1. 数字按键0-9 .使用的效果;
  2. C DEL /使用的效果;
  3. * - + =使用的效果;

修改按钮的背景需要使用selector drawble。首先用数字按钮举例。

5.3.2.1 数字按键效果

  1. 打开res\values\colors.xml文件,定义没有按下按钮时背景的颜色为#D0DCE3按下按钮时背景的颜色为#BED1DB

  2. res\drawable\目录下,点击右键,启动创建drawable resource的向导;

  3. 创建selector drawable的xml文件,文件名为digital_btn_selector.xml

  4. 根据Button是否被按下的状态android:state_pressed,分别为它们设置不同的颜色,android:state_pressed=true,说明当前按钮被按下,android:state_pressed=false,说明当前按钮没有被按下;设置颜色使用@color关键字,并加上之前在colors.xml中定义的颜色的名字;

  5. 给数字按键7Button设置android:background属性,使用drawable selector,

    这样就能看到数字按键的效果了。

5.3.2.2 浅色按键效果

  1. 定义没有按下按钮时背景的颜色为#BED1DB按下按钮时背景的颜色为#66A1B4

  2. 创建selector drawable的xml文件,文件名为symbol_light_btn_selector.xml

  3. 给按键CButton设置android:background属性,使用drawable selector,

5.3.2.3 深色按键效果

  1. 定义没有按下按钮时背景的颜色为#66A1B4按下按钮时背景的颜色为#78CCE6

  2. 创建selector drawable的xml文件,文件名为symbol_dark_btn_selector.xml

  3. 给按键*Button设置android:background属性,使用drawable selector,

5.3.3 使用style来实现三种不同的效果

要修改所有的按钮效果,可以给每个Button使用android:background属性增加对应的背景,但是这样就需要修改很多地方。

为了减少修改每个Button的工作量,可以将上面Button的3种显示效果各定义成一种style,然后再为Button设置对应的style就可以了。
先以数字按键为例,来定义style。

5.3.3.1 数字按键style

  1. 打开res\values\styles.xml文件;
  2. Button的共同特性定义成一个style---DigitalBtnStyle;此外,为了键盘美观,通过定义android:layout_margin属性,增加了每个按钮的间距。

  3. 为所有数字按钮设置style属性,添加DigitalBtnStyle风格;

5.3.3.2 符号浅色按键style

  1. res\values\styles.xml文件中,定义SymbolLightBtnStyle

  2. C DEL /按钮设置style属性,添加SymbolLightBtnStyle风格;

5.3.3.3 符号深色按键style

  1. res\values\styles.xml文件中,定义SymbolDarkBtnStyle

  2. * - + =按钮设置style属性,添加SymbolDarkBtnStyle风格;

5.3.4 使用style来实现显示区域的效果

显示区域也可以使用style

  1. res\values\styles.xml文件中,定义一个TextAreaStyle

  2. 使用TextAreaStyle

至此,计算器界面美化完成。

安豆计算器 第4节 计算器功能实现

第4节 计算器功能实现

这一节我们将实现计算器的功能。在实现的过程中,可以随时将修改的代码部署到设备上,看看实际的效果。

4.1 添加按钮响应

按钮是需要在用户点击的时候做出响应的。每当用户点击一下按钮,我们就需要更新一下显示区域,或者采取一个动作。

  1. 在布局文件中,给所有Button控件的android:onClick属性设置一个响应函数,这里我们给这个相应函数也取名叫做onClick

  2. MainActivity.java的源代码当中,添加对应的onClick()函数方法。这个方法声明为public,返回值为void,传入的参数是View,这个View就是被点击的对象;

  3. 每次点击的是哪个按钮,可以用按钮的android:id来区分。在代码中,id通过Android Studio自动编译生成的R-资源类来访问,形如R.id.xxx;而获取一个Viewid,可以通过view.getId()

  4. 为了验证按钮响应是否其作用,可以在onClick()函数中使用Toast;在设备上运行之后,就会发现,每点击一次按钮,就会弹出一个小框,提示“onClick”;

4.2 表达式输入功能

当用户点击数字键(0-9和.)以及运算符键(+-*/)时,需要将它们对应的符号显示到表达式区域。

  1. view转换成Button类型,通过ButtongetText()方法,获取按钮上的字符;
  2. 通过Activity的findViewById()方法获取表达式区域;在通过表达式区域TextViewgetText()方法,获取已经显示在表达式区域上的内容;
  3. 把按钮代表的字符,添加到表达式内容的最后;
  4. 把新的表达式内容,通过TextViewsetText()方法,显示到表达式区域上。

4.3 显示区域清除功能

当用户点击“C”按钮的时候,清空显示区域的内容和结果区域的内容。

  1. 通过Activity的findViewById()方法,分别获取表达式区域和结果区域;
  2. 通过TextViewsetText()方法,分别为它们设置空字符串。


当用户点击“DEL”按钮的时候,删除表达式内容的最后一个字符。

  1. 获取表达式区域的内容;
  2. 如果表达式区域是空的,没有字符串,就不管它;否则利用String类的subString()方法,截取最后一个字符之前的所有内容;
  3. 将最新截取的内容,设置到表达式区域里。

4.4 等于功能

当用户点击“”按钮的时候,开始计算。

4.4.1 引入第三方库

我们将使用第三方计算库Arity对表达式进行计算。Arity库文件可以在安豆网提供的下载地址进行下载。

下载完成后,

  1. 将下载的arity-2.1.2.jar复制到项目工程所在的Calulator\app\libs目录下,如果这个目录不存在,就自己创建一个;
  2. 在Android Studio左边的项目浏览区,选择Project视图;
  3. app->libs->arity-2.1.2,jar上点击右键,选择Add as Library...
  4. 在弹出的选择框中,点击OK

4.4.2 使用第三方库

利用第三方库,对运算表达式进行计算,

  1. 获取表达式区域的内容;
  2. 创建第三方库Arity提供的Symbols对象,使用它的evl()方法,计算表达式的内容;
  3. 将计算结果显示到计算结果区域,并清空表达式区域;
  4. 如果Arity不能根据提供的计算表达式进行计算,会抛出异常。因此使用try...catch抓住异常,用Toast类给用户一个内容为错误!的提示。

至此,一个具有计算功能的计算器就已经出现了。

安豆计算器 第3节 计算器界面布局

第3节 计算器界面布局

现在起,我们就开始正式开发“计算器”应用。这一节,我们将完成计算器的界面布局,让它初具计算器的模样。

计算器界面是通过布局文件定义的。它位于项目的res\layout\activity_main.xml文件中。

这个布局文件通过java源代码MainActivity.java中的setContentView()函数,设置到界面上。

接下来,我们的界面布局,就会在这个布局文件activity_main.xml中进行。
在修改布局文件的过程中,可以通过Preview功能,来实时观看我们修改的界面布局效果。

3.1 上下段布局

首先确定布局形式。界面分为两个大区域,上半区域显示计算表达式和计算结果,下半区域显示键盘。

  1. 两个区域一上一下,呈线型排列,因此我们选择LinearLayout布局;
  2. 通过将LinearLayoutandroid:orientation属性设置成vertical来将它包含的内容以竖直方式排列;
  3. 整个界面将尽可能占用整个屏幕,因此使用match_parent指定布局的宽度和高度。match_parent说明尺寸要尽可能的大。

  1. 上半区域包含了表达式区域和计算结果区域,它们也成竖直排列,所以还需要一个LinearLayout包含它们。上半区域占整个界面的1/3,就要将android:layout_weight设置成1android:layout_height设置成0dp
  2. 下半区域是键盘的显示区域,我们也选用LinearLayout作为这个区域的布局。下半区域占整个界面的2/3,就要将android:layout_weight设置成2android:layout_height设置成0dp

这样的设置说明,要将父布局剩余的空间平均分成1+2=3份,上半区域分得1/3,下半区域分的2/3。所谓空余的空间就是:父布局的空间,被子布局的空间占用后,所剩余的空间。

布局文件中,我们将现实区域和键盘区域的高度都设置成了0dp,说明它们在竖直方向上不占用任何空间,但是又设置了layout_weight,说明它们要按照父控件match_parent占用的高度来按比例分配。

3.2 显示区域布局

结果区域和表达式区域一上一下,各占一半空间,用来显示文字内容。它们可以使用TextView控件来实现。

  1. 为结果区域指定android:idresult_areaandroid:layout_weight设置成1android:layout_height设置成0dp
  2. 为表达式区域指定android:idformula_areaandroid:layout_weight设置成1android:layout_height设置成0dp
    设置了id,我们以后就可以在代码中,通过这id来获取并使用这个控件了。
  3. 包含结果区域和表达式区域的LinearLayout设置android:orientation属性为vertical,让它们竖直排列
  4. 为了祛除界面上四个边的空白,我们还要移除最外层LinearLayoutandroid:paddingXXXX这几个属性,让整个界面填满显示区域。

3.3 键盘区域布局

键盘布局可以进一步分成左右两个区域,

  1. 左边区域是C DEL 0-9以及.
  2. 右边区域是* - + =

这两个区域,可以同样使用水平排列的LinearLayout作为它们的父布局,

  1. 左边区域像个表格,可以使用TableLayout,让它占据3个单位的宽度,android:layout_weight设置成3android:layout_width设置成0dp
  2. 右边区域就是一个简单的竖直排列的LinearLayout,让它占据1个单位的宽度,也就是android:layout_weight设置成1android:layout_width设置成0dp

3.3.1 键盘左区域布局

键盘按钮分成3*5格,每一格就是一个按钮,这就像是一个表格,所以我们选用了TableLayout作为它们的布局。

  1. 每一行用TableRow表示,它是与TableLayout配合使用的布局,用来表示表格的每一行;这里有5行,就添加5个TableRow
  2. TableRow在默认情况下,会假定android:layout_widthmatch_parentandroid:layout_heightwrap_content,我们就简单的在这里设置一个android:layout_weight1

键盘上的按钮可以使用Android SDK提供的Button控件,

  1. 通过android:text属性为每个Button设置需要显示的内容;
  2. 为它们各自的android:id取上对应的id名字;
  3. 每一行的Button还是按照相等的比例进行分配,android:layout_width设置成0dpandroid:layout_weight设置成1android:layout_height设置成match_parent
  4. 最后一行中的‘0’按钮,它要占据两列的宽度,我们可以将这个Button控件的android:layout_weight设置成2,就能让它能够占据2格的位置了;

3.3.2 键盘右区域布局

最后,我们将键盘右边区域的按钮添加上。

  1. Button竖直排列,就要将包裹它们的LinearLayout设置android:orientationvertical
  2. 这一列的Button还是按照相等的比例进行分配,所以android:layout_height设置成0dpandroid:layout_weight设置成1android:layout_width设置成match_parent

至此,计算器的界面布局就完成了。

安豆计算器 第2节 应用的创建与部署

第2节 应用的创建与部署

这一节我们会创建一个全新的项目工程,编译后,让它运行到设备上。

2.1 创建应用工程

启动Android Studio,选择Start a new Android Projcet


进入项目设置的界面一:

  1. Application name栏,为应用取个名字为Calculator
  2. Company Domain栏,按照网址的形式填上anddle.com--当然,你也可以根据自己的喜好填上别的域名;
  3. Project location栏,填写应用存放的位置,可以选择任意你希望存放项目工程的目录。

选择下一步后,进入项目设置界面二:

  1. 勾选上Phone and Tablet
  2. Minimum SDK的选择,要与调试设备的安卓版本尽量一致。

*手机版本与API等级的对应关系如下:


选择下一步后,进入项目设置界面三:

  1. 选择Empty Activity

选择下一步后,进入项目设置界面四:

  1. Activity Name栏,Activity采用默认的名字MainActivity
  2. Layout Name栏,layout文件也采用默认的名字activity_main

选择完成后,工程创建完成。

*因为Android Studio是第一次创建项目工程,因此需要连接网络下载一些组件,需要多等待一些时间。一旦下载成功,以后创建工程就不会花费这些时间了。

2.2 部署应用到设备

为了验证我们创建的工程,我们需要把生成的项目,编译成Apk,然后部署到设备上运行。

要在设备上进行调试,首先要打开设备的开发者选项,不同品牌的安卓设备界面虽然不尽相同,但使用方式都大同小异:

  1. 启动安卓设备上的“设置”应用,进入“关于手机”选项卡;
  2. 连续点击“版本号”,直到出现您现在处于开发者模式!的提示信息;

  3. 返回上级菜单,进入“开发者选项”,开启调试模式,钩上USB调试;


将手机和电脑用USB数据线连接起来。

在Windows系统,需要为连接上的设备安装ADB驱动:

  1. 安豆网资源下载下载ADB的Windows驱动到电脑本地;
  2. 在“我的电脑”上点鼠标右键,选择“管理”,打开“设备管理器”,可以看到没有安装驱动的设备;
  3. 为它更新驱动,选择“浏览计算机查找”,

  4. 指定下载的ADB驱动目录位置,点击确定后,驱动很快就安装成功了。

  5. 点击Android Studio的Android Monitor窗口,就能看到这个连接上的设备了,这个窗口还输出了手机端打印的运行信息。


将应用部署到设备上:

  1. 点击菜单栏中的绿色的小三角;

    或者使用Debug快捷按键shift+F10

  2. 在选定的设备上双击,

    此时就可以在设备上看到,我们的程序运行起来了。


至此,我们成功的创建了一个可以在设备上运行的空项目工程。