1、关于项目
MarkNote 是一款 Android 端的笔记应用,它支持非常多的 Markdown 基础语法,还包括了 MathJax, Html 等各种特性。此外,你还可以从相机或者相册中选择图象并将其添加到自己的笔记中。这很酷!因为你可以将自己的游记或者其他图片拍摄下来并将其作为自己笔记的一部分。这也是笔者开发这款软件的目的——希望 MarkNote 能够成为一款帮助用户记录自己生活的笔记应用。
下面是我自己制作的一张部分功能预览图。这里仅仅列举了其中的部分页面,当然,你可以在酷安网或者 Google Play Store 上面获取到这个应用程序,并进一步了解它的全部功能,也可以在 Github 上得到最新版的应用的全部源代码。
项目相关的链接:
- 酷安网下载链接:https://www.coolapk.com/apk/178276
- Google Play Store 下载:https://play.google.com/store/apps/details?id=me.shouheng.notepal
- Github 项目链接:https://github.com/Shouheng88/MarkNote
最后,之所以把这次重构称为 “承上启下” 的一个很重要的原因是:这次重构代码其实是为了后续功能的开发铺路。在未来,我会为这个应用增加更多有趣的功能。如果你对该项目感兴趣的话,可以 Star 或者 Fork 该项目,并为项目贡献代码。我们欢迎任何的、即使很小的贡献 ?
2、关于重构
在之前的版本中,MarkNote 在功能、界面和代码方面都存在一些不足,所以,前些日子我又专门抽了些时间对这些不足的地方进行了一些优化,时间大概从 11 月中旬直到 12 月中旬。这次重构也进行了大量的代码优化。经过这次重构,项目增加了大概 100 多次 commit. 下面我们列举一下本次重构所涉及的部分,其实也是这段时间以来学习到的东西的一些总结。
2.1 项目结构优化
2.1.1 包结构优化
首先,在之前笔者已经对项目的整个结构做了一次调整,主要是将项目中各个模块的位置进行了调整。这部分内容主要是项目中的 Gradle 配置和项目文件的路径的修改。在 settings.gradle
里面,我按照下面的方式指定了依赖的各个模块的路径:
include ':app', ':commons', ':data', ':pinlockview', ':fingerprint'
project(':commons').projectDir = new File('../commons')
project(':data').projectDir = new File('../data')
project(':pinlockview').projectDir = new File('../pinlockview')
project(':fingerprint').projectDir = new File('../fingerprint')
这种方式最大的好处就是,项目中的 app
, commons
, data
等模块的文件路径处于相同的层次中,即:
--MarkNote
|----client
|----commons
|----data
....
这个调整当然是为了组件化开发做准备啦,当然这样的结构相比于将各个模块全部放置在 client
下面清晰得多。
其次,我将项目中已经比较成熟的部分打包成了 aar
,并直接引用该包,而不是继续将其作为一个依赖的形式。这样又进一步简化了项目的结构。
最后是项目中的功能模块的拆分。在之前的项目中,Markdown 编辑器和解析、渲染相关的代码都被我放置在项目所引用的一个模块中。而这次,我直接将这个部分拆成了一个单独的项目并将其开源到了 Github.
这么做的主要目的是:
- 将核心的功能模块从项目中独立出来单独开发,以实现更多的功能并提升该部分的性能;
- 开源,希望能够帮助想实现一个 Markdown 笔记的开发者快速集成这个功能;
- 开源,希望能够有开发者参与进行以提升这部分的功能。
关于 Markdown 处理的部分被开源到了 Github,其地址是:https://github.com/Shouheng88/EasyMark ,该项目中同时还包含了一个非常好用的编辑器菜单控件,感兴趣的同学可以关注一下这个项目。
2.1.2 MVVM 调整
在该项目中,我们一直使用的是最新的 MVVM 设计模式,只是可惜的是在之前的版本中,笔者对 MVVM 的理解不够深入,所以导致程序的结构更像是 MVP. 本次,我们对这个部分做了优化,使其更符合 MVVM 设计原则。
以笔记列表界面为例,当我们获取了对应于 Fragment 的 ViewModel 之后,我们统一在 addSubscriptions()
方法中对其通知进行订阅:
viewModel.getMutableLiveData().observe(this, resources -> {
assert resources != null;
switch (resources.status) {
case SUCCESS:
adapter.setNewData(resources.data);
getBinding().ivEmpty.showEmptyIcon();
break;
case LOADING:
getBinding().ivEmpty.showProgressBar();
break;
case FAILED:
ToastUtils.makeToast(R.strin