安卓开发(一)时间管理应用DayPlay
《时间管理:从优秀到卓越》- 提升个人效率的实用策略 #生活常识# #时间管理建议# #时间管理书籍推荐#
本篇主要讲本科时写的一个app。从应用开发的流程到最后代码落到实地,涉及设计模式、代码编写等相关知识。代码https://github.com/goodluckcwl/DayPlan
需求分析:
日常生活中,人们常常会因为拖拉而无法按时完成任务。“你有多少时间,就会花多少时间做一件事”,似乎是常人的通病。也许你开始时踌躇满志,目标明确,可是时间一长往往就会偏离目标,将时间浪费在一些无谓的事情上。缺乏适时的、足够多的提醒是主因。
当前,市场上有足够多的优秀日程管理应用,如Wunderlist等。这些应用大多提供日程记录、日程优先级、闹钟提醒、同步等功能。但这些应用的任务事项时间跨度都比较大、期限也比较长,提醒功能比较被动。这虽然有利于把握大的方向,但对于短期内效率的提高不一定有很好的效果。从另一个角度上看,养成良好的时间管理习惯,既需要着眼于长远的目标,也需要有具体的、可行的短期实践方案。所谓短期,我认为一天比较合适。
本应用并不致力于像Wunderlist一样具有十分全面的功能。而是专注于为拖拉者做好一天(甚至更短)的规划,通过主动的、多次的提醒及时检查、纠偏,让拖拉者逐渐成长为高效的成功人士。
设计理念:
一天计划,任务事项的主动、多次提醒,及时纠偏。 1
基本功能:
1、添加任务功能:可以添加任务事项,包括任务描述,任务属性(4类:重要紧迫、重要不紧迫、紧迫不重要、不紧迫不重要),任务标签,截止时间,图片等
2、提醒功能:包括两个模式:①普通模式:任务截止时间提醒②强迫模式:根据不同的任务属性,间隔一定的时间提醒一次
3、根据任务标签的搜索功能
4、分享:微信、QQ等
扩展功能:
提醒内容的自定义、任务完成情况总结表单等(待定) 1
DayPlan最终效果
DayPlan打开后,首先显示一个任务列表,如图1,任务列表左侧以不同颜色标记任务的紧迫性,同时可以看到任务的标题、日期、截止时间、是否完成等信息。
用户点击某项任务后,将进入编辑页面,在该页面可以修改任务标题、截止时间,添加提醒等。
在编辑界面点击相机按钮,进入拍照界面
在编辑界面点击图片,进入查看图片界面,用户可以放大照片查看细节在任务截止时间到了的时候,DayPlan弹出一个窗口,给出简短的提醒信息
功能详细描述
(一)规划功能:
用户可以在前一天晚上做好第二天的规划,添加必要的任务事项,包括任务描述,任务的紧迫性(重要紧迫、重要不紧迫、紧迫不重要、不紧迫不重要),截止时间,并且可以添加一张相关的图片作为提示。
(二)提醒功能
用户可以为每个事项添加提醒功能,每当截止时间到的时候,DayPlan给出一个简短的提醒。DayPlan致力于在提醒用户的同时不过分打扰用户。
(三)分享功能
DayPlan可以从某个任务生成一个描述该任务的字符串,并分享到其他应用。
系统架构设计
根据经典的MVC设计模式,我们把系统划分为三层:模型层、视图层、控制层。
(一)模型层
模型对象存储着DayPlan的应用数据和业务逻辑。模型对象不关心用户界面,它存在的唯一目的就是存储和管理应用数据。DayPlan的模型对象主要是管理图片的Photo类、管理任务事项的Plan类、进行数据存储的DayPlanJSONSerializer类、应用运行过程中保存数据的数据池单例类SinglePlanLab类等。
(二)视图层
视图对象知道如何在屏幕上绘制自己及如何响应用户的输入,DayPlan中的视图对象主要由layout文件中定义的各类组件构成。比如ZoomImageView类就是一个可以响应用户手势进行图片缩放的视图对象。
(三)控制层
控制对象包含应用的逻辑单元,是视图与模型的联系纽带。控制对象响应视图突发的各类事件。在DayPlan中,控制对象主要由Fragment类的各个子类构成。
最后,给出DayPlan应用总体框图
各子模块介绍
(一)模型层子模块
模型层主要的模块是数据处理模块、数据存储模块。
1、数据处理模块
主要由类Photo、类Plan、类SinglePlanLab处理。分别介绍如下:
①Photo类:保存图片路径的类。
②Plan类:保存任务事项的类。包含任务标题、任务截止时间等成员变量。
以上两个类均提供了从JSON对象获取数据的构造器及转化为JSON对象的方法,以方便数据存储。
③SinglePlanLab类:保存应用中所有Plan对象的单例类。为了保证数据的同步,应该把整个应用中的所有Plan对象集中保存在一个单例类里,这样数据就只有一份。其他对象从SinglePlanLab对象获取需要的Plan对象的引用。因为其他对象获取的只是SinglePlanLab对象中Plan池中某个Plan的引用,所以当其他对象修改Plan时,实际上是对SinglePlanLab中的Plan对象进行操作,所以可以保证SinglePlanLab中的Plan将会得到同步更新。
这里贴一下SinglePlanLab.java的代码:
package cn.edu.zju.isee.www.dayplan; import java.io.File; import java.util.ArrayList; import java.util.Date; import java.util.UUID; import android.content.Context; import android.util.Log; public class SinglePlanLab { private static final String TAG ="SinglePlanLab"; private static final String FILENAME ="plans.json"; private static SinglePlanLab sPlanLab; private ArrayList<Plan> mPlans; private DayPlanJSONSerializer mSerializer; private Context mContext; private SinglePlanLab(Context context){ mContext=context; // mPlans=new ArrayList<Plan>(); mSerializer=new DayPlanJSONSerializer(mContext, FILENAME); // mPlans.add(new Plan("","今天要去跑步")); // mPlans.add(new Plan("","信息论与编码还有复习")); // mPlans.add(new Plan("","嵌入式系统设计课程作业")); // mPlans.add(new Plan("","网络安全课程大作业期末...........")); try{ mPlans=mSerializer.loadPlans(); //创建1000条信息用于测试 Log.d(TAG,"load plans"); }catch(Exception e){ Log.d(TAG,"plans.json doesn't exist,create empty planLab"); mPlans=new ArrayList<Plan>(); } } public static SinglePlanLab getInstance(Context context){ if(sPlanLab==null){ sPlanLab=new SinglePlanLab(context); } return sPlanLab; } public void addPlan(Plan plan){ mPlans.add(plan); } public void deletePlan(Plan plan){ mPlans.remove(plan); } public Plan getPlan(int index){ Plan p; try{ p=mPlans.get(index); }catch(Exception e){ Log.d(TAG,"getPlan out of range,return null"); return null; } return p; } public Plan getPlan(UUID planId){ for(Plan p:mPlans){ if(p.getId().equals(planId)){ return p; } } return null; } public ArrayList<Plan>getPlans(){ return mPlans; } public int getLength(){ int result=0; for(Plan plan:mPlans){ result++; } return result; } public ArrayList<Plan> getPlanByLabel(String label){ ArrayList<Plan>result=new ArrayList<Plan>(); for(Plan plan:mPlans){ if(plan.getLabel().equals(label)){ result.add(plan); } } return result; } public ArrayList <Plan> getPlanByType(String type){ ArrayList <Plan>result=new ArrayList<Plan>(); for(Plan plan:mPlans){ if(plan.getType().equals(type)){ result.add(plan); } } return result; } public ArrayList <Plan>getPlanByDate(Date date){ ArrayList<Plan>result=new ArrayList<Plan>(); for(Plan plan:mPlans){ if(plan.getDate().equals(date)){ result.add(plan); } } return result; } public Boolean savePlans(){ try{ mSerializer.savePlans(mPlans); Log.d(TAG,"plans saved to file"); return true; }catch(Exception e){ Log.d(TAG,"error save plans"); return false; } } public void clearPlans(){ File f=new File(mContext.getFilesDir()+"/"+FILENAME); if(f.exists()){ mContext.deleteFile(FILENAME); } mPlans.clear(); } }
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361372、数据存储模块
DayPlan中处理数据保存的类是DayPlanJSONSerializer。在DayPlan中需要保存的数据是SinglePlanLab中的所有Plan类实例。DayPlan应用采用JSON保存数据,过程如下:
首先,Plan类包含了一个转化为JSON对象的方法、一个从JSON对象获取数据并构造Plan实例的构造函数。保存数据时首先将Plan实例转化为JSON实例。
然后,DayPlanJSONSerializer类负责将JSON对象保存到应用的内部空间。
读取数据时,DayPlanJSONSerializer从文件读取数据并构造JSON对象,然后调用Plan的构造函数构造Plan对象。
由于SinglePlabLab维护着整个应用的数据,所以数据的保存与读取由SinglePlanLab负责。SinglePlanLab类知道如何使用DayPlanJSONSerializer类读取与保存数据。
(二)控制层子模块
根据应用的功能,可将控制层划分为5个子模块:添加任务模块、删除任务模块、提醒模块、拍照模块,分享模块。
1、添加任务模块
主要由类PlanListFragment与PlanEditFragment类处理。当用户在任务列表界面点击某个任务的时候,PlanListFragment启动PlanEditFragment并把用户所点击任务的对应的Plan实例的UUID传递给PlanEditFragment。PlanEditFragment利用UUID从SinglePlanLab获取Plan对象并初始化视图。
用户修改数据后,PlanEditFragment从视图层获取数据,对Plan实例作相应的修改,完成更新数据层的功能。
2、删除任务模块
主要由PlanListFragment类处理。当用户在任务列表界面长按操作时,进入删除模式,可以选择多个任务并删除。PlanListFragment负责告知模型层哪些任务被删除了。
3、提醒模块
主要由类PlanEditFragment和AlarmActivity类处理。当用户点击“提醒我”按钮时,PlanEditFragment启动一个TimePicker,用户输入时间后,PlanEditFragment调用系统闹钟服务,在设定的时间启动AlarmActivity,AlarmActivity则根据Plan的内容弹出提醒窗口。
4、拍照模块
主要由类PlanEditFragment和PlanCameraFragment处理。当用户点击相机按钮后,PlanEditFragment启动PlanCameraActivity(管理PlanCameraFragment的Activity)。PlanCameraFragment使用系统相机API完成拍照、处理图片、保存图片的功能,并把图片路径传递给PlanEditFragment,PlanEditFragment根据图片路径生成一个Photo对象并添加到Plan实例里。最后,PlanEditFragment刷新视图层,用户将看到刚刚拍摄的照片的缩略图。
5、分享模块
主要由类PlanEditFragment处理。当用户点击“分享”按钮时,PlanEditFragment根据当前的Plan实例,生成一个包含任务标题、任务截止时间、任务紧迫情况、任务完成情况的字符串,然后将该字符串附加到一个隐式Intent里,启动其他应用,实现分享功能。
(三)视图层子模块
DayPlan的界面主要有:任务列表界面(图1),编辑界面(图2),拍照界面(图3),查看照片界面(图4)等。
1、任务列表界面
该界面需要显示多个任务,并且根据用户的上下滑动加载不同的任务并显示。使用ListView可以方便地解决这个问题。
2、编辑界面、拍照界面
编辑界面由布局文件fragment_edit_plan.xml完成。此外,为了实现左右滑动切换到不同任务的编辑界面,我们使用PlanPagerActivity(包含ViewPager成员)来管理PlanEditFragment。
拍照界面由布局文件fragment_plan_camera.xml完成。
3、查看照片界面
DayPlan自定义了一个ZoomImageView类,负责响应用户手势进行图片的缩放。ZoomImageView类继承自View类,包含一个Bitmap成员。ZoomImageView类检测用户的手势操作,根据手指的坐标计算出图片缩放的比例,通过重写View的OnDraw函数,将Bitmap按照所计算的缩放比例绘制到屏幕上。在用户看来,就像进行了图片的缩放一样。
总结
DayPlan实现了一个时间管理应用的基本功能,但尚有以下不足:
DayPlan根据一段时间的任务完成情况绘制统计图的统计功能尚未完成;DayPlan在查看照片模式中进行图片缩放的时候,流畅度与系统自带照片查看软件相比还有差距;DayPlan在拍照过程中,由于直接调用了硬件相机,实现起来相对复杂,且拍照过程中亮度无法自动调节。但直接调用相机应用的方法则无法获得全尺寸的照片,不能满足DayPlan的需求;DayPlan在拍照后处理图像的过程中由于没有使用多线程,阻塞了UI线程;DayPlan在加载图片的过程中阻塞了UI线程;DayPlan的界面有待美化。
DayPlan这些不足有待后续完善。
网址:安卓开发(一)时间管理应用DayPlay https://www.yuejiaxmz.com/news/view/204395
相关内容
5款安卓好用的时间效率管理APP(安卓好用的时间管理软件)安卓进程管理
“小目标”终于有救了!iHour安卓版发布:最好用的时间规划应用
卓越员工必备技能:时间管理
时间安排软件app有哪些?比较好的时间安排管理app推荐
时间管理清单app
统计了一下目前安卓手机系统维护时间:
天天日程管理安卓下载
时间小贴士——摘自安卓软件“时间管理小助手”
国内十大应用商店 安卓应用商店排名 好用的手机软件商店