数据库方面
概述
由于这个应用涉及到本地存储笔记应用,所以需要用到Android的ORM框架(Object-Relational Mapping),市面上有好多ORM框架,例如: GreenDao
、OrmLite
、Afinal中的FinalDb
、Realm
等等。这次我采用的是FinalDb
这个框架来进行数据的本地存储。下一款应用我打算用Realm
或者GreenDao
来做数据存储,之后也可以对比下这几个框架的优劣。下面我会记录一些我在使用FinalDb
这个框架时候遇到的一些问题和总结。另外,FinalDb
框架的增删改查源码分析会抽空专门写一篇来进行研究。
使用总结
对象初始化
|
|
db对象初始化是用FinalDb
类中的静态方法create
方法来创建的,在create
方法的内部逻辑中,会判断以NConstant.NOTE_DB_NAME
这个名字命名的数据库是否已经存在,如果不存在,就会新建;如果存在,则会返回该数据库对象。在实际应用中,如果数据库是从res-raw
资源文件夹中拷贝到sd卡上的,则需要在拷贝结束后,再初始化db对象。因为一般在拷贝前,先会判断数据库是否已经存在,如果已经初始化db对象,数据库文件已存在,则不会执行拷贝操作。
查找排序
在某个笔记本下呈现全部笔记的页面里,会将最近操作过的笔记放在最前面的位置,所以从数据库读取笔记时,需要按时间进行降序排列
,具体的实现代码是:
|
|
而如果是需要升序排列
,则把DESC
改成ASC
。
说到了时间排列的问题,另外还要记录一下的就是,数据库存储的最近更新时间有两个格式,一个是字符串类型
,一个是long类型
,其中字符串类型的时间带上了时区信息,便于记录笔记是在哪个时区的哪个时间创建或修改的,这样就避免了因为换时区,导致显示的时间不同的问题;long类型的时间就是为了降序排列而记录的。
非某个名字的查找
下面的代码是用来查找除了某个名字之外的其它所有内容:
|
|
事件发布方面(EventBus)
在笔记类应用中,由于在修改、移动、删除笔记操作时,都会伴随着其它页面的一些变动,所以也就需要一个消息总线来发布事件,订阅事件以实现程序间组件的通信,这里我选择了用得比较多的一个框架–EventBus
。
3.0.0版本的EventBus
中register
和post
两种方法与之前版本相同,但是在事件处理
的方式上有了很大的不同,例如之前使用的方法是:
|
|
而在3.0.0版本以后,使用注释来说明事件处理的线程:
|
|
在刚开始进行开发时,对于发布的事件没有进行封装,这样一来,post
出去的事件在处理的时候没有起到作用,例如在移动笔记时,会涉及到两个笔记本的数量变动,没有进行封装前,就会将全部的笔记本重新初始化一遍,这样的性能可想而知是不会高的。在后来的优化中,将涉及到的笔记本、笔记本的位置和笔记本操作类型(分为移动笔记和创建笔记本两种)封装成NoteBookEvent
,在post
的时候将NoteBookEvent
对象发布出去,进而在处理事件时,只针对相关的笔记本进行操作,而不是全部笔记本初始化一遍。
印象笔记接入方面
多彩笔记在功能设计时,就把接入印象笔记作为功能之一。在实际开发中,还是遇到了一些细节上的问题,值得记录下来。
登录回调
印象笔记的登录回调支持两种模式:
onActivityResult
方法里面判断requestCode
是否是EvernoteSession.REQUEST_CODE_LOGIN
以及resultCode
是否是RESULT_OK
,如果是,则说明登录成功,接下来就是去获取用户信息的操作:evernote.getUser()
。- 另一种方式是实现
ResultCallback
接口,但是在多彩笔记应用里,由于Activity
不是FragmentActivity
,所以在实现ResultCallback
接口的回调中,没法获取到用户登录是否成功的信息。
多彩笔记在印象笔记里的专属笔记本
印象笔记的机制是:对于每个第三方接入的应用,由应用本身创建一个专属的笔记本用来同步笔记。所以在每次同步笔记之前,都要先检查专属的笔记本是否存在,如果不存在,则需要创建,具体实现方法是Evernote
类里的makeSureNotebookExist(@NonNull String notebookName)
。
相同笔记多次同步如何避免在印象笔记里重复出现
印象笔记会个每条笔记设置一个唯一的guid
,所以多彩笔记里,也把guid
当作笔记的唯一识别码存储起来,在每次同步笔记时,会检查本地笔记的guid
是否有值,如果没有,则说明是第一次上传,这样就需要创建一条印象笔记;如果有,则说明是更新笔记的操作,无需创建新的一条印象笔记。
单向同步(多彩笔记->印象笔记)
多彩笔记只做了单向同步到印象笔记功能,除了我觉得对于小的笔记类应用来说,所产生的笔记大部分都只会向印象笔记汇聚,而没有必要进行反向同步,因为这类笔记应用的用户粘性不会高。还有一个原因是,多彩笔记也有笔记本的概念,同步到印象笔记之后,原有的笔记本信息没有办法保存,在进行反向同步时,也就没法找到原来的笔记本,所以也就索性没有做反向同步这个功能。
软键盘方面
由于笔记里面需要键盘输入操作,所以要用到Android打开键盘以及关闭键盘的API,但是在实际开发以及测试过程中,目前还没有发现封装两个接口可以解决所以键盘打开和关闭的操作,所以这里只是把我在开发过程中遇到的一些情况给记录下来:
从一个Activity跳入另一个Activity需要自动打开键盘,有一个方法可以实现:
- 1getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
其它开启关闭键盘有效方法:
- 1234567891011121314public static void hideKeyboard(Activity activity) {InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);imm.hideSoftInputFromWindow(activity.getWindow().getDecorView().getWindowToken(), 0);}public static void hideKeyboard(Context context, View view) {InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);imm.hideSoftInputFromWindow(view.getWindowToken(), 0);}public static void showKeyboard(Context context) {InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);}
上面hideKeyboard
方法是在键盘关闭,关闭activity,键盘不会重新打开
情况下也可以使用的,因为用户在输入文字之后,可能在键盘关闭或者打开的情况下去关闭activity
,所以需要一个无论什么情况都能让键盘关闭的方法才能满足需求。
一些小问题
AsyncTask
里的execute
方法只能执行一次,如果重复执行,会导致程序崩溃,所以正确的处理是每次都new
一个AsyncTask
对象来进行操作- 可滑动侧边栏
drawerLayout
设置背景颜色的方法drawerLayout.setScrimColor(getResources().getColor(R.color.black_transparency_12));
FloatingActionButton
在xml文件里由layout_gravity
设置时,初始化进入页面设置setVisibility
为gone
,会出现闪动一下再消失,影响美观;如果采用app:layout_anchor+layout_anchorGravity
来对位置进行设置,则用setVisibility
方法就不会有闪动的问题。- 在笔记页面里,出现保存的“对勾”按键是由四个纬度来判断的:
- 笔记内容改变,出现保存按键
- 笔记标题改变,出现保存按键
- 所在笔记本改变,出现保存按键
- 笔记内容和笔记标题长度有一个不为零,出现保存按键