结对编程项目

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

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. html中实现倒计时功能(setInterval,clearInterval)

    倒计时主要用到的知识点:1.设置时间间隔的setInterval可以被clearInterval取消 2.毫秒转换为时分格式 这个是效果图 下面是js中的函数 var shijian=3600; va ...

  2. JAVA 各种锁机制

    可重入锁 可重锁是指同一个线程,外层函数获取锁后,内层函数可以自动获取到锁. java中synchronized和ReentrantLock都是可重入锁. 对于synchronized,其实现机制有j ...

  3. [AngstromCTF 2019]Cookie Cutter

    最近看到了一个国外高中生的CTF比赛,翻了一下往年的例题,发现有一道关于jwt session伪造的题比较有意思,记录一下 题目简介中给出了我们题目的地址和后端处理的源码,看看源码先代码审计一下: c ...

  4. OpenvSwitch系列之八 vxlan隧道

    Open vSwitch系列之一 Open vSwitch诞生 Open vSwitch系列之二 安装指定版本ovs Open vSwitch系列之三 ovs-vsctl命令使用 Open vSwit ...

  5. 【小白学PyTorch】8 实战之MNIST小试牛刀

    文章来自微信公众号[机器学习炼丹术].有什么问题都可以咨询作者WX:cyx645016617.想交个朋友占一个好友位也是可以的~好友位快满了不过. 参考目录: 目录 1 探索性数据分析 1.1 数据集 ...

  6. 非构造函数方式创建DbContext实例的方法

    using Microsoft.EntityFrameworkCore;using Microsoft.EntityFrameworkCore.Design;using Microsoft.Entit ...

  7. AP、AC、无线路由器

    起因 AP.AC.无线路由器 一直都傻傻的分不清,今天就好好的研究一下他们之间到底有什么联系和区别~ AP 什么是AP? 无线AP(Access Point):即无线接入点,它用于无线网络的无线交换机 ...

  8. 如何制作一个手机上的Github图床捷径(workflow)

    准备工作 github账号与绑定邮箱 建立一个仓库用于存放图片 生成github token 注意生成之后要备份以免后面要用到(页面刷新之后会看不见) 了解github上传文件的 GitHub API ...

  9. flutter driver 集成测试

    最近一直断断续续的学习flutter,今天跟大家介绍一下flutter driver测试. flutter测试基础 Flutter的测试遵循Android的测试规范进行了分层. 单元测试:测试单一功能 ...

  10. Css3新增的特性(1)

    CSS3 模块 CSS3被拆分为"模块".旧规范已拆分成小块,还增加了新的. 一些最重要CSS3模块如下: 选择器 盒模型 背景和边框 文字特效 2D/3D转换 动画 多列布局 用 ...