结对编程项目

软件工程 这就是链接
作业要求 这就是链接
作业目标 熟悉在未结对情况下如何结对开发项目

Github与合作者

合作者(学号):

  • 区德明:318005422
  • 虚左以待

Github链接:

https://github.com/DMingOu/CalculateExercise

由于本来的合作者临时有事不能和我一起结对编程,所以我也只好咬咬牙单刀赴会了。

因为本次的题目要求有图形化界面,而我也学过移动开发的,所以一不做二不休,直接提刀杀进AndroidStudio,开始秃头设计一款小学生也能用的四则计算题练习工具App,一来可以简化方便操作和展示,二来也算是在众多.exe中里面可以独树一帜。

一、PSP

PSP2.1 Personal Software Process Stages 预估耗时 (分钟) 实际耗时 (分钟)
Planning 计划 25 38
· Estimate · 估计这个任务需要多少时间 25 38
Development 开发 945 830
· Analysis · 需求分析 (包括学习新技术) 75 130
· Design Spec · 生成设计文档 100 80
· Design Review · 设计复审 60 35
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 30 60
· Design · 具体设计 120 110
· Coding · 具体编码 260 260
· Code Review · 代码复审 60 45
· Test · 测试 (自我测试,修改代码,提交修改) 95 110
Reporting 报告 120 105
· Test Repor · 测试报告 60 50
· Size Measurement · 计算工作量 30 30
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 30 25
· 合计 1090 973

二、四则运算练习工具APP需求分析

需求描述 是否实现
控制生成题目的个数
控制题目中数值范围
计算过程不能产生负数,除法的结果必须是真分数,题目不能重复,运算符不能超过3个
显示题目
显示答案
能支持一万道题目的生成
判定答案中的对错并进行数量统计
显示得分结果
具有图形化的操作界面

三、APP开发计划

功能 描述 开发者 进度
生成题目 随机生成操作数和运算符,组成有效的四则运算表达式 区德明 完成
计算结果 根据生成的表达式,计算生成正确的结果 区德明 完成
练习报告 输出成绩结果 区德明 完成
UI界面设计 设计软件的界面设计XML 区德明 完成
UI界面实现 使用Kotlin语言实现 Andoid APP 区德明 完成
功能测试与故障修复 测试程序的功能,修复出现的故障 区德明 完成
性能分析与优化 分析程序执行的性能,优化性能表现 区德明 完成

结构图

四、方案

4.1 生成题目的算法设计思路

线程池多线程并发,创建指定数量的题目,并利用Set集合进行去重操作。

核心代码如下:

执行生成题目的线程任务类

    /**
* 执行生成指定数量题目任务
* 线程类
*/
private class GenerateWorker(
private val exerciseNum: Int, //生成数量
private val numRange: Int, //范围上限
private val workerIndex: Int, //工作线程的编号
private val countDownLatch: CountDownLatch,
private val tempList : MutableList<Exercise>
) : Runnable {
override fun run() {
try {
val start = System.currentTimeMillis()
val exerciseList = generateExercises(
exerciseNum, numRange
)
//将 去重但是未编号的 列表 加入缓冲列表中
tempList.addAll(exerciseList)
countDownLatch.countDown()
} catch (e: Exception) {
e.printStackTrace()
}
}
}

执行完善收尾操作的线程任务:

    /**
* 用于补充题目序号, 完善,的任务
*/
private class SupplyWorker(
private val exerciseNum: Int,
private val countDownLatch: CountDownLatch,
private val tempList : MutableList<Exercise> ,
private var startIndex : Int ,
private val mHandler: QuestionListHandler //回调UI线程
) : Runnable {
override fun run() {
getExerciseOnCount(exerciseNum)
countDownLatch.countDown()
//根据已有的列表数据,进行编号
for(exercise in tempList) {
startIndex++
exercise.number = startIndex
}
updateGlobalExerciseList(tempList)
//通知 View层更新内容
val message = Message()
message.what = 666
mHandler.dispatchMessage(message)
}
}

提供给外界调用的入口:

fun produce(exerciseNumber: Int, numberRange: Int,startIndex : Int, handler: QuestionListHandler) {
if (exerciseNumber == 0 || numberRange == 0) {
return
}
//最小范围是2
if (numberRange < 2) {
throw RuntimeException("范围上限不可以少于2")
}
//手工计时器启动
start = System.currentTimeMillis() //设置本次加载的起始序号
this.startIndex = startIndex //每个线程的工作量
val workload = 25
//记录线程编号
var index = 1
//剩余工作量
var remainWorkload = exerciseNumber
//启动创建题目的线程组
val threadCount = if (exerciseNumber % workload == 0)
exerciseNumber / workload
else
exerciseNumber / workload + 1
//生成线程+一个输出线程
countDownLatch = CountDownLatch(threadCount + 1) //任务正式启动前。清空缓存列表,避免脏数据
tempExerciseList.clear() while (true) {
//执行生成题目的任务线程,编号对应
remainWorkload -= if (remainWorkload > workload) {
execute(
GenerateWorker(
workload,
numberRange,
index++,
countDownLatch,
tempExerciseList
)
)
workload
} else {
execute(
GenerateWorker(
remainWorkload,
numberRange,
index,
countDownLatch,
tempExerciseList
)
)
break
}
}
//启动完善每一道题的任务
execute(SupplyWorker(exerciseNumber, countDownLatch ,tempExerciseList ,startIndex , handler))
//数据创建完毕,重置状态
countDownLatch.await()
clear()
}

生成题目的操作,实际执行:

    @JvmStatic
fun generateExercises(exercisesNum: Int, numRange: Int , startIndex : Int = -1): List<Exercise> {
//控制编号
var index = startIndex
//如果没有传入编号则视为生成时不做编号处理
val isSetIndex = index!=-1
//控制生成循环的结束
var count = 0
val exerciseList: MutableList<Exercise> = ArrayList()
while (count < exercisesNum) {
val exercise = generateQuestion(numRange)
generateAnswer(exercise)
//有效题目加入List
if (validate(exercise)) {
count++
if(isSetIndex) {
index++
//设置序号
exercise.number = index
}
//生成可以输出的题目样式
EXERCISE_QUEUE.add(exercise)
exerciseList.add(exercise)
//放入去重Set,用作判断
exercisesSet.add(exercise.simplestFormatQuestion)
}
}
return exerciseList
}

4.2 客户端(用户入口)的设计思路

采用单Activity+多Fragment的架构。

  • util包提供算法和数据源的能力
  • View包承载页面UI的显示,
  • bean包存放实体类信息
  • widget包存放的是一些自定义控件

五、效能分析

通过大厂滴滴的开源性能工具平台,DoKit,接入App,进行性能的进一步分析,如下:

5.1 程序效能

使用APP的出题功能,分别生成1000道,2000道,10000道题目不同的消耗内存情况

  • 生成1000道题目时,只需要130MB
  • 生成2000道题目时,只需要155MB
  • 生成10000道题目的时候,就需要1005MB了

可以认为题目的数量影响着App的运行时所消耗的资源及内存,并随着题目的数量成正比例关系。

cpu消耗如下:

页面打开跳转的时长:

5.2 性能优化

首轮优化

可以看出线程池的线程配置对于大数据量非常重要,从生成10000条题目为例子,在4个线程在并发的创建对象的时候,因为设置的单个线程任务量为2000,无法完成剩下的2000任务,只能等4个线程任务都完成后再创建新线程执行任务。

解决方案:调整线程池的配置,提高线程的数量,提高每个生成题目的线程的任务数量
优化后的结果:

线程池复用线程,分页加载50条数据,逐步的加载出全部的数据,分散内存和CPU的密集消耗。

优化后的生成10000条数据,耗时从10秒提高到了7秒,提升了30%。如果继续对线程池的配置进行优化,效率还会继续提高。

进一步优化

但是对于移动应用来说,加载时间的耗时始终是大问题,让用户觉得等待时间过长,同时会有卡顿的问题,亟待解决,所以下面要通过性能分析工具,分析哪个步骤流程才是在生成题目列表的过程中造成卡顿呢??通过DoKit的卡顿堆栈分析图:

可以看出卡顿 与 打开页面,创建对应数据,数据创建后,列表UI开始加载数据, 频繁大量地创建View对象息息相关。

进一步解决方案:分页加载

数据量过大的时候,其实不需要一口气全部加载进去,可以采用分页加载的方式加载与创建对象,吞吐量减少的同时CPU和内存的占用也降低了。从另一个角度讲,页面也无必要一口气加载上千条乃至万条的数据 ( 屏幕就这么大 ,用户看不过来)

设定分页加载题目的方式,每页固定数量为 50 ,若所需数量不足50条,则继续加载所需的数量题目。

打开性能检测平台的监控 CPU,内存 ,帧率

未加载数据前:

打开页面,加载10000条数据:

可以看出,优化后,加载大数据,对页面的影响小了很多,CPU和内存的短时间消耗急剧降低,对App这种只拥有固定内存(少量)的进程,可以有很不错的效果。

六、APP真机测试报告

6.1 测试1:程序生成四则计算题和答案是否符合题目要求

结果说明:

以上为测试生成100道数值10以内的题目的截图

可以得出结论,看到题目是符合去重的要求且答案是正确的

6.2 测试2:程序是否能正确判断用户输入答案的正确性

以 6 道题目为例子,查看练习情况报告,可以看到可以给出正确答案提示,以及完成的情况,错对情况,得分率,很详细。

6.3 测试3:能否支持一万道题目的生成与显示

在出题模式下执行生成10000道数值范围在5以内的题目的功能

最终效果

首页 题目列表
练习做题 练习情况报告

七、总结

项目小结

获得的经验:

虽说只是做了一个小工程,从中也学习到了多线程的相关知识,数据结构的使用和APP界面的设计与布局。

不足的地方:

没有做查看历史做题的历史记录。

生成大批量的题目的时候,会随着页面加载越来越多的题目,随着RecyclerView持有的子itemView数量逐渐增多会导致分页加载,RecyclerView时会有卡顿感。

结对感受

期待ing,个人感觉是各司其职,对方请教时再给建议,要结合实际情况,不过分追求效果。

这就是小学生也会用的四则计算练习APP吗?- by软工结对编程项目作业的更多相关文章

  1. 3.结对编程成果报告(小学生四则运算的出题程序,Java实现)

    程序名称:小学生四则运算的出题程序 先附上代码: package com.makequestion; import java.text.DecimalFormat;import java.util.R ...

  2. 软工作业NO.2小学生线上杨永信——四则运算题目生成

    项目题目:实现一个自动生成小学四则运算题目的命令行程序 github地址:https://github.com/a249970271/Formula 驾驶员:梁沛诗 副驾驶:曾祎祺 项目说明 自然数: ...

  3. 【BUAA软工】结对编程作业

    项目 内容 课程:2020春季软件工程课程博客作业(罗杰,任健) 博客园班级链接 作业:BUAA软件工程结对编程项目作业 作业要求 课程目标 学习大规模软件开发的技巧与方法,锻炼开发能力 作业目标 完 ...

  4. 【Beta阶段】展示博客

    Beta阶段展示博客 blog software buaa 1.团队成员简介 Email:qianlxc@126.com Free time:8:00 7:00 a.m ~ 11:00 12:00p. ...

  5. [2017BUAA软工助教]第0次作业小结

    BUAA软工第0次作业小结 零.题目 作业链接: This is a hyperlink 一.评分规则 本次作业满分10分: 按时提交有分 一周内补交得0分 超过一周不交或抄袭倒扣全部分数 评分规则如 ...

  6. [2017BUAA软工助教]个人项目小结

    2017BUAA个人项目小结 一.作业链接 http://www.cnblogs.com/jiel/p/7545780.html 二.评分细则 0.注意事项 按时间完成并提交--正常评分 晚交一周以内 ...

  7. 【个人项目总结】C#四则运算表达式生成程序

    S1&2.个人项目时间估算 PSP表格如下: PSP2.1 Personal Software Process Stages Time(Before) Time(After) Planning ...

  8. [BUAA软工]第二次博客作业---结对编程

    [BUAA软工]结对作业 项目 内容 这个作业属于哪个课程 北航软工 这个作业的要求在哪里 2019年软件工程基础-结对项目作业 我在这个课程的目标是 学习如何以团队的形式开发软件,提升个人软件开发能 ...

  9. [BUAA软工]第一次博客作业---阅读《构建之法》

    [BUAA软工]第一次博客作业 项目 内容 这个作业属于哪个课程 北航软工 这个作业的要求在哪里 第1次个人作业 我在这个课程的目标是 学习如何以团队的形式开发软件,提升个人软件开发能力 这个作业在哪 ...

随机推荐

  1. 【转】LeakCanary

    LeakCanary:检测所有的内存泄漏 http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0509/2854.html 原文: L ...

  2. Activiti7 表介绍

    由于Activiti自生成的表较多,这里先对activiti自生成数据库表进行介绍. 数据库表的创建在后续的demo文章中进行介绍,并且后续会写一篇关于数据库详解的文章,这里先大概知道Activiti ...

  3. JVM学习第二天(垃圾回收器和内存分配策略)大章

    说道垃圾回收器大家应该都会有所了解,GC白,当然说道具体的可能就不是很清楚了,今天我们就来玩一玩; GC要做的事情: 第一步:确定堆中需要回收的对象; 第二步:什么时候回收; 第三步:怎样回收 为什么 ...

  4. 【Azure DevOps系列】使ASP.NET Core应用程序托管到Azure Web App Service

    使用Azure DevOps Project设置ASP.NET项目 我们需要先在Azure面板中创建一个Azure WebApp服务,此处步骤我将省略,然后点击部署中心如下图所示: 此处我选择的是Az ...

  5. 阿里云短信服务验证码封装类 - PHP

    本文记录在ThinkPHP6.0中使用阿里云短信验证码,该封装类不仅仅局限于TP,拿来即用 使用该类之前必须引入 flc/dysms 扩展,该封装类就是基于这个扩展写的 composer requir ...

  6. 案例:ADG环境遇到redo日志member路径有误以及RMAN-6571错误

    最近先后帮客户做了两套从虚拟化环境到物理机的数据库迁移,都是Linux系统,Oracle 11.2.0.4的RAC,最终选定ADG方案实现迁移,简单高效. 在之前的文章Oracle 11g ADG 部 ...

  7. odoo提示你没有查看此类文档的权限

    问题: odoo出现提示信息:"抱歉, 你没有访问此类型文档的权限 '未知' (_unknown). 没有为此操作指定权限组 - (操作: read, 用户: 2)" 出错原因: ...

  8. React 和 VUE 的区别和优缺点

    前言 React 是由Facebook创建的JavaScript UI框架,React推广了 Virtual DOM( 虚拟 DOM )并创造了 JSX 语法.JSX 语法的出现允许我们在 javas ...

  9. python之ddt模块使用

    一.DDT(数据驱动)简介 Data-Driven Tests(DDT)即数据驱动测试,可以实现不同数据运行同一个测试用例(通过数据的不同来驱动测试结果的不同). ddt本质其实就是装饰器,一组数据一 ...

  10. python 3 for与while嵌套