写在前面
大学生活一下子就过去两年了,在这里也小小地感慨一下,时间过得好快哦。最近心情比较复杂,所以大学生活究竟过得怎么样,先不予置评。就像《岁月如歌》说的那样:
天气不似如期
但要走 总要飞
生活总是要继续的,生活中也还有很多我所珍视的东西。WakeUp课程表作为自己首个独立作品,看着它从最原先的简陋,到现在基本功能还是都有了,且界面还是差强人意的,我还是有点成就感的。我不知道自己还能对它维护多久,可能到大三也就不更了?看心情吧,当然也希望有人能接下这个工作。所以就写下这篇东西。查看项目点这里。如果你还不知道这个App长什么样,可以在主流的应用商店搜索“WakeUp课程”,或者点击这里。
负责任地说,其实入门Android并不需要掌握全部的Java特性,我当时也算是一边写Android一边加深对Java的理解(其实到现在也还是在高级特性边缘试探?)现在Google宣布Kotlin成为Android官方开发语言,Kotlin看起来会简洁很多。也一直想用Kotlin重构项目,还是看心情吧😶瞬间感觉自己很佛系了。
废话就不多说了,还是推荐两本书吧,《Java编程思想》和《第一行代码:Android(第2版)》,两本都比较厚,后面那本很适合Android入门。
这篇文章不是教你怎么进行Android开发,只是让你知道如果想修改某个功能应该去哪里找。下面的内容如果暂时没看懂没关系,可以慢慢来。我会在其中穿插一些开发知识来帮助理解;如果是大佬在阅读过程中觉得项目架构有问题(我自认为是有问题的),恳请指出。右边有一个目录,可以快速跳转到自己需要看的位置。
项目总览
如果你没有安装Android Studio,这个目录结构跟你在文件夹里看到的是不太一样的,真实的文件夹包裹得有点深,不过相信聪明的你多点几下就能有所发现。下面按照这个结构来介绍各部分的大致内容。
manifest
这个文件夹下的AndroidManifest.xml是一般Android项目都有的一个配置文件,是一个文本文件,可以用任何的文本编辑器打开。
下面的内容是声明了App需要用到的权限,第一项是互联网访问的权限,第二项是存储空间写的权限。互联网访问的权限一旦声明,App就可以访问网络连接的;Android有一些是敏感权限,比如这里的存储空间读写权限,在Android 5.0之后除了在这里声明,还需要动态去申请权限。
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
下面这个部分是由application标签包裹的代码块,实际上比较长。android:icon指明了App的图标,android:label指明了App的显示名称。省略号部分就是注册了各种activity、service等组件,这方面可以去自行搜索“Android四大基本组件”,此处就不展开了。
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
……
</application>
java
所有的Java代码都集中在这个文件夹里面了,这里你会看到它有三个子文件夹,这是新建项目自动生成的,一般看第一个,其它两个跟测试相关(我也没用过)。
com.suda.yzune.wakeupschedule
其实java下面的三个子文件夹都叫上面这个名字,后面两个在后面会有(test)等标注。这个长长的名字叫应用包名,用于来唯一标识Android应用。可以看到这里又有很多子文件夹,这些文件夹都是我手动创建的,是为了分类然后便于查看,这个分类不是很细致,有点马虎的,但是还是能很快定位到自己要查看的代码。
adapter
这些Adapter都是ListView、RecyclerView或者ViewPager的Adapter(好像说得有点废……)。
- ClassTimeAdapter是关联了设置页面-上课时间里面,那个选择第几节是什么时候开始的RecyclerView。
- OtherCourseAdapter是关联了侧栏-我要蹭课里面可蹭课程的列表。
- SchedulePagerAdapter这个添加的时间不长,是为了做主界面左右滑动切换周数加的,关联了主界面那个ViewPager。
- TodayCourseAdapter是关联了侧栏-今日课程里面的课程列表。
model.bean
这里主要存放了一些自己定义的数据类:
- AppWidgetBean:用于管理桌面小部件的数据类,也是和数据库GreenDao中表字段对应的数据类,记录了小部件的id和类型(日视图为0,周视图为1)。
- Course:课程表最核心的数据类,课程表主界面看到的一个色块对应就是一个Course对象。
- UpdateInfo:更新信息的数据类,每次检查更新时都会把服务器返回的数据解析成这种对象。
后面两种数据类一般都是搭配Gson来使用的,也就是用Gson对象把它们对应的对象生成json字符串,或者是用Gson对象把相应的json字符串解析成相应的对象。
下面说明一下Course类:
public class Course {
private String name, room, teach, id, campus;//课程名称、上课教室、授课老师
//这个id是用来存放手动调整颜色的编号的、campus是用来标记苏大校区的
int start, step, day, startWeek, endWeek, isOdd;
//开始上课节次、课程的长度(比如两节课就为2)
//day是指星期几(周一day的值为1)
//isOdd用来标记单双周(0为全周,1为单周,2为双周)
long num;
……
}
service
这个service就是用来放后台服务代码的,而且都是关于桌面小部件的更新服务。
- ListViewService:负责每日课程小部件中列表的更新。
- ScheduleWidgetService:负责周视图小部件中课程的更新。
utils
集中存放工具类,不过有点杂乱。诶……感觉如果要解释可以新写一篇博文了。这里就简单说一说好了。
- BaseDao、DaoManager、DaoUtils、WidgetDaoManager:对GreenDao封装的工具类,在小部件相关的代码可以看到它们的身影。我是很迟才在项目中引入了数据库这个工具,同类的App好像一开始就是用数据库来储存课程信息的,羞愧羞愧。
- Config:目前这个工具类没有用,里面放的是语音识别服务的密钥之类的,之前想做一个语音输入课表的功能,奈何识别准确率太低。
- Constants:里面放了一些常量,比如教务系统网址、验证码网址,还有检查更新的地址等。
- CourseUtils:跟课程处理有关的工具类,但是里面放的东西比较杂。makeCourseTogether这个函数是针对从苏大教务获取的课程分节的情况的,让相同的连续的课程结合在一起;post这个函数是将苏大课程传回服务器的;showCampusChoose用来显示对话框来让苏大学生选择所在校区;calAfterTime用来计算下课时间。
- DisplayUtil:跟显示相关的工具类,里面有几个常用的单位转换函数,比如dp转换成px。
- DonateUtils:跟捐赠有关的工具类,里面是有冗余代码的,有用的是isAppInstalled这个函数,用来检测某个App是否安装了,我用来检测支付宝是否安装了。
- GlideAppEngine:这个是为了让知乎开源的图片选择库兼容Glide新版本,而继承的一个类。
- JsonUtils:只是用来检测Json是否合法的工具类,运用在侧栏-恢复那里。
- MyCookieJar:模拟登陆时需要的……可以不用管。
- MyRadioGroup:其实这个不应该放在工具集合这里,这是自定义的单选按钮组,修改课程颜色的时候你会看到它,原生的RadioGroup不能分行。
- OkHttpUtil:这个是很重要的封装了OkHttp的工具类,主要用于模拟登陆教务系统。
- SharePreferencesUtils:这个类可以很方便地将int、String、boolean等数据通过SharePreferences储存起来,也可以取出来。因为项目中大量用到了SharePreferences,课程信息和设置都是通过这个储存起来的😂
- UpdateUtil:检查更新的代码在里面。
- ViewUtil:里面只有一个函数,就是取消activity的toolbar以及使其顶栏沉浸。
啊,这部分终于粗略地介绍完了。
view
接下来是这个view了,顾名思义,view就是我们能够看到的视图部分,所以这里面放的都是直接负责App界面操作的代码,当然后面还会说到它们对应的布局代码。
- AboutActivity:点击 侧栏-关于 出现的界面,里面的内容除了App版本号以外,其他部分都是固定的,版本号会随着工程文件的变化而变化。
- DecodeActivity:这个我没有把入口暴露出来,它是一个解析苏大教务课程HTML的界面,大体上就是把网页源码复制到上面,就可以生成课程表。
- DonateActivity:捐赠页面,如果想把捐赠的支付宝账号改成自己的,修改里面的qrcode_url即可。
- FixActivity:电脑义修页面,核心函数是startQQChat,会根据里面的参数发起QQ聊天。
- IntroActivity:如果是一路升级过来的朋友应该不会看到这个页面,这个是寒假的时候加入的引导页。里面使用了一个第三方开源库,关于项目中开源库的使用会在下文集中说明。
- LoginXKActivity:刚开始课程表登录苏大教务是用网页形式登录的,不太友好。而这个是那个友好的登录页面。模拟登录、HTML解析的代码都在这里,把一个activity写得这样“胖”是不太好的,这里我确实没有把模块分离好。尤其是HTML的解析代码其实在项目中复制着用了好几次,这个完全可以封装成一个工具类的。
- MainActivity:这个就是我们一开始的网页登录界面,里面有一个WebView。然后课程解析部分的代码跟上面的是重复了的。我的建议是,除非你有十足的把握,不然还是不要改动,因为这里涉及到了Java对JavaScript的调用。这个页面保留着,是因为少数人用上面的界面登录会遇到验证码一直错误的问题,如果错误次数多了,就会开放这个页面的入口,用网页的形式进行登录。
- ScheduleActivity:这个就是日常我们见到的主界面。在之前,它负责了课程的显示,还有侧栏也是依托在这里的;现在,在主界面支持左右滑动切换每周课程后,它不再直接负责课程的显示,而是在刷新界面时计算当前周数。当我们介绍到它对应的布局时,你应该会更加清晰一点。
- SettingsActivity:设置界面,在这里你会看到SharePreferencesUtils工具类的频繁使用,因为这些设置的参数都是以SharePreferences的形式保存的。
- ShareActivity:侧栏-分享/备份的界面,里面有个函数对系统剪贴板进行操作,里面也能找到属性动画的运用例子。
- ThemeSettingsActivity:侧栏-自定风格的界面,部分设置项跟SettingsActivity有重复。里面本来有一个主界面背景模糊程度的调节功能,但是我测试起来有点小问题,就是设置后会有模糊效果,但是这个模糊效果不随设置的数字改变而改变。
- TimeSettingActivity:设置-设置上课时间的界面,里面有个RecyclerView,上面在说Adapter的时候有提到。
- TodayCourseActivity:今日课程的界面,我个人感觉这个比较少人打开……
- ViewOtherCourse:蹭课的界面,我发现 你好苏大 是有蹭课接口的,到时候可以研究研究。
上面的都是activity,下面介绍一下fragment。每个fragment都是依赖于上面的某个activity的。
- Intro1Fragment、Intro2Fragment、Intro3Fragment:配合IntroActivity使用的,对应三个引导界面。有部分设置现在是放到引导界面去设置的,比如在第二个引导界面设置是苏大的还是其他大学的。这三个界面不算得很精致,如果可以的话要重新设计一下。
- ScheduleFragment:配合ScheduleActivity使用。ScheduleActivity在初始化时会新建25个ScheduleFragment对象,对应25个周,由于Android的回收机制,这个对性能的影响不太大的。目前发现的问题是旋转屏幕时界面会空白,这可能跟Fragment的生命周期有关。
还会看到下面还有ScheduleWidget和TodayWidget,对应两种桌面小部件。我个人感觉目前网上关于AppWidget的资料都是翻译了一下官方文档,或者是太旧了,反正怎么都不太符合业务需求。我会考虑写一篇单独介绍AppWidget的文章。
MyAppGlideModule
你也许会注意到这个虽然在java文件夹下,但是也不属于上面的任何一个子文件夹。这个是为了解决Glide这个图片加载库新旧版的兼容性问题,不能删除。
res
终于把java这个文件夹介绍完了。现在轮到res了,这是resource的简写,里面主要存放的是项目的资源文件,包括xml文件、图片等。
anim
这是存放动画xml文件的文件夹,logo_jump.xml是第一个引导页面的小鹿飞跃动画效果的控制文件。
drawable
这个文件夹里是各种图片资源,文件实在太多了截图截不过来,各个文件分别是什么用途,可以打开下面的布局文件去查看。一般来说,App的体积大小主要取决于资源文件的大小。加入新的图片时应该注意适当压缩一下图片,在质量和大小之间把握平衡。还有要注意命名要有规律,有规律的命名可以让自己一看就知道这个资源是用在哪里的(我这里的命名也不是特别规范,因人而异)。
layout
这里就是布局文件了,绝对要比上面的Java代码要有意思,因为在Android Studio中,这些布局文件都是可视化的,下面是一个例子:
这是我们的登录界面,中间部分的代码改动会在右边的可视化界面体现出来。不过右边的可视化界面并不是100%还原的,比如我们实际运行时看到的登录界面是没有粉红色的工具栏的。借助这个基本实时的可视化界面,你可以自由地修改我们现有的界面。
看到中间界面左上角那个C按钮了吗?点击它就可以跳转到对应界面的Java代码。同样,在Java代码显示区的左上角,也有一个跳转到布局文件的按钮,可以很方便地来回切换。布局文件和Java代码一起看,会加深你对其功能的理解。
menu
这个是用来放菜单的,而里面只有一个文件,这个是关于侧栏菜单内容的文件。当你点开它时,它是下面这样一个界面:
这跟上面的可视化界面不太一样,但是不影响你去修改它。可以看到,一个item对应一个菜单的选项,可以指定它的id、图标和标题。
mimap
这里放的是App启动图标,ic_launcher.png就是App的启动图标,有很多个不同尺寸的版本。fix_launcher.png和today_launcher.png是shortcuts中显示的两个图标,shortcuts不是所有ROM都支持的,你可以尝试一下长按课程表App的启动图标,看看有没有shortcuts出现。
values
这里放着一些资源常量,比如颜色、字符串、styles等等。在写这个项目的时候没有考虑过项目国际化的问题……所以无论你的系统是什么语言,App都只有简体中文。如果要做项目国际化的话,需要在strings.xml定义。嗯……工作量是有点大的。
xml
这里是一些配置文件而不是资源文件。其中:
- schedule_widget_info.xml和today_widget_info.xml都是桌面小部件的配置文件,配置了小部件的更新频率、初始化尺寸等信息。桌面小部件会另开一篇来写。
- shortcuts.xml是shortcuts的配置文件,是静态的。一般来说静态的也够用了,感觉shortcuts这个功能并没有普及开来……
项目总配置
Gradle Scripts里面是项目总体的配置,一般来说只需要修改两个文件,其他文件最好不要修改。
上面说的两个文件它们的实际名字都是一样的,都是build.gradle,不过实际存放在不同的文件夹里,作用也不太一样。
- build.gradle(Project:……)这个一般在添加第三方库的时候需要配置一下。
- build.gradle(Module:app)这个可以修改的地方就很多了,下面举些例子。
minSdkVersion 21
targetSdkVersion 27
versionCode 19
versionName "2.10"
上面这段中:
- minSdkVersion是项目最低sdk的版本,决定了你的应用最低可以安装在哪个Android版本上,这里的21是指Android 5.0,也就意味着Android 4.4上无法安装这个App。一般来说要兼容更低的Android版本会增加你的工作量。
- targetSdkVersion是项目的目标sdk版本,如果你要用到新平台的新特性,就需要修改这里。
- versionCode后面是一个数字,用来表示版本更迭,每一次推出正式的更新是都应该增加这个数字。
- versionName后面跟的是一个字符串,其实也不一定要是数字字符串,可以弄一些好玩的,每个版本之前有区分度就行。
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:27.0.2'
compile 'com.android.support:support-v4:27.0.2'
compile 'com.android.support:design:27.0.2'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.google.code.gson:gson:2.7'
compile 'com.squareup.okhttp3:okhttp:3.9.0'
compile 'com.android.support:cardview-v7:27.0.2'
compile 'com.github.apl-devs:appintro:v4.2.2'
compile 'com.github.GrenderG:Toasty:1.2.8'
compile 'com.tapadoo.android:alerter:2.0.0'
compile 'com.zhihu.android:matisse:0.4.3'
compile 'com.github.bumptech.glide:glide:4.6.1'
compile 'com.github.florent37:glidepalette:2.1.2'
compile 'jp.wasabeef:glide-transformations:3.1.0'
compile 'org.greenrobot:greendao:3.2.2'
annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1'
testCompile 'junit:junit:4.12'
}
上面这一段是我们用来添加第三方库的,下面会介绍项目中第三方库的使用情况。
第三方库的使用情况
support库
上面以com.android.support开头的就是support库,这些support库可以使App在各个版本保持同样的用户体验,比如在Android 5.0以下系统使用Material Design。如果想对它了解更多,可以参考这篇文章:Android Support Library的前世今生。
OkHttp库
OkHttp是具有高效的请求效率的网络请求库,项目中把其进行再次封装成为一个工具库。学习网络请求方面的知识,可以参考:OkHttp使用完全教程。
Gson库
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,常见于网络数据的传送。在项目中不仅用于网络数据的传送,还将其用于信息的本地存储。而Gson,是一个Google的一个解析和生成Json的开源库。可以参考:你真的会用Gson吗?Gson使用指南。
AppIntro库
AppIntro库可以让你快速生成美观的引导界面,GitHub地址在这里,里面有开发者写的使用文档,能满足一般使用。
[站外图片上传中...(image-783b74-1523195636642)]
Toasty库
Toasty库是用来代替系统自带的Toast通知的,Toasty的样式更加多,还允许很方便地自定义样式,GitHub地址在这里,里面有开发者写的使用文档,能满足一般使用。
Alerter库
Alerter库在项目中用作用户操作的提醒,很有动感,比较醒目,GitHub地址在这里,里面有开发者写的使用文档,能满足一般使用。
[站外图片上传中...(image-e89646-1523195636642)]
matisse库
matisse是知乎开源、界面优美的图片/视频选择库,可以自定义主题,以及定义一些过滤规则等,而且集成起来还是很方便的。项目GitHub地址在这里,里面有使用文档,能满足一般使用。
[站外图片上传中...(image-6ec6f4-1523195636642)]
[站外图片上传中...(image-3031e9-1523195636642)]
Glide库
Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide给我的感觉是很强大的,在网上的教程也非常多。GitHub地址在这里,然后这里有一份中文文档。
[站外图片上传中...(image-a2a40a-1523195636642)]
GlidePalette库
GlidePalette是一个配合Glide使用的取色库,可以提取图片中明亮、鲜艳、主要等颜色,最多有6种取色方案,可以令图片很好地与环境融合。项目GitHub地址在这里,里面有使用文档,能满足一般使用。
[站外图片上传中...(image-a9eb28-1523195636642)]
glide-transformations库
glide-transformations是一个配合Glide使用的变换库,可以将在显示时变换图片,比如高斯模糊、或者黑白化、或者让图片圆形显示。项目GitHub地址在这里,里面有使用文档,能满足一般使用。
greenDAO库
greenDAO是一款开源的面向Android的轻便、快捷的ORM框架,将 Java对象映射到SQLite数据库中,我们操作数据库的时候,不在需要编写复杂的SQL语句,在性能方面,greenDAO针对Android进行了高度优化,最小的内存开销、依赖体积小同时还支持数据库加密。项目GitHub地址在这里,这个库个人感觉需要阅读多几篇教程才行,自己搜索丰衣足食哦。
好啦,以上就是第三方库的使用情况,我也是做过很对比才决定使用它们的,它们也没有让我失望啦。当然它们能够发挥更为出彩的,前提是要了解得更为深入。
结语
如果你看到了这里,非常感谢你的耐心,这篇只是初略地讲了一下项目目前的大体情况,可能在你看来没有什么干货。做这个项目我还是收获了很多的,不过整理起来都需要时间。码一篇博文还是蛮累的,还是贵在坚持吧。