月度归档:2017年02月

开发 Diycode Android 客户端的记录

开发 Diycode Android 客户端的记录。

整体

  1. 项目整体采用 MVP 结构

    主体位于 model 包下,又根据各个功能模块进行了分包,每个子包中进行 MVP 的实现。

    一开始只是进行了 MVP 的划分,很快就发现编辑代码时经常在几个大包之间跳转,于是就在 MVP 之上加了一层功能模块的划分。

  2. 各模块之间通过 EventBus 进行事件通信和解耦

    每个模块的 Event 都定义在其 event 包中,在 Presenter 中进行 register 和 unregister。

    EventBus 推荐的 register 和 unregister 时机在 onStart 和 onStop,原本也是照这样写的。但是后来引入SwipeBack 库时就发现 unregister 不被调用,查了一番才发现 SwipeBack 要求继承透明主题,导致跳转新 Activity 时 onStop 并不会被调用,因此将 register 和 unregister 时机调整到了 onResume 和 onPause。

  3. 定义 BaseActivity 和 BaseFragment

    统一的功能点修改起来会方便很多。例如调整 EventBus 的 register 和 unregister 时机时,只需要在 BaseActivity 和 BaseFragment 调整就好了。

功能点

  1. 网络请求

    网络请求采用 Retrofit 库,对于 REST 结构的 API,使用起来很方便。而且 Retrofit 支持 RxJava,如果需要支持引入 RxJava,改起来也方便。

    调试接口推荐 Chrome 应用 Postman。

    Diycode 的接口地址中普遍包含 api/v3,只有 token 相关的接口中没有包含,这导致我在声明 Retrofit 对象的 baseUrl 时纠结了很久,因为并不想因为一个接口导致其他所有的接口声明中都需要加上 api/v3。后来发现如果在声明接口时使用绝对路径的话是可以覆盖掉声明 Retrofit 对象时定义的 baseUrl 的。

  • @Path 声明请求路径中的参数;
  • @Header 声明请求头中的参数;
  • @GET 请求的参数用 @Query 声明;
  • @POST 请求的参数用 @Field,用 @FormUrlEncoded 声明参数的编码格式;
  • @DELETE 请求中默认不允许包含 body,如果需要包含(例如取消赞的接口),需要使用 @HTTP(method = “DELETE”, path = “likes.json”, hasBody = true)。
  1. 图片加载

    图片加载使用的 Glide 库。

    资源文件中的大多数图片都是我从 material.io 下载 SVG 图片后,在 AndroidStudio 使用 Asset Studio 转成的 vector drawable 图片。但是 Glide 不支持 vector drawable,所以主要用在了在 xml 中声明过的图片的显示上。

    话题详情中的图片点击会跳转至一个可以用手势放大图片的 ImageActivity,这个手势操作图片的功能主要是 PhotoView 这个库实现的。集成这个库是个曲折的过程,主要是在显示 GIF 格式的图片时经常加载不出来,甚至我一度引入了 Facebook 的 Fresco 库来解决这个问题,后来查来查去发现是需要 diskCacheStrategy(DiskCacheStrategy.SOURCE) 这个配置。

  2. RecyclerView

    引入了 MultiType 来简化 RecyclerView 的使用。避免了需要展示多种类型的数据时在一个 Adapter 中需要太多代码的问题。

  3. SwipeBack

    引入了 swipebacklayout 来实现。需要注意的是由于需要继承透明主题,导致 onStop 不调用的问题。

  4. 话题详情的展示

    这部分真的是痛苦,先是需要处理图片显示宽度的问题,再是代码块的换行问题,最后还有渲染效果的问题。

    折腾许久摸不着门道后,引入 MarkdownView-Android 使用接口返回的 markdown 格式的数据直接渲染,效果也还不错。但是有个问题就是 RecyclerView 滑动时会被回收然后重新加载,体验不好。过了一段时间就又开始研究使用 WebView 加载 html 格式的数据,参考了 oschina 开源的客户端源码(此处以后还可以进行修改,去除一些不必要的东西),对着网页版的 diycode 试着改 css 文件,终于改成了现在的样子。

    这其中还掺杂了一个有趣的事情,我只要打开 WebActivity,话题详情中的 WebView 就再也不展示数据了。摸索了好久才发现 WebActivity 的 onPause 中会调用 pauseTimers,这个会导致所有的 WebView 暂停布局、解析、JS运行。

  5. 话题评论的展示

    具体看 HtmlUtil.removeP 这个方法。接口返回的数据是 html 格式的,由于评论很多,所以在 TextView 中展示的。但是返回数据中前后经常会加 <p> </p> <br> 这种东西,导致 TextView 上下老是有空白出现,所有就需要提前加工下数据。

  6. Token 的加密保存和解密

    恰好看到了 Android 密钥保护和 C/S 网络传输安全理论指南 这篇精彩的博文,所以就参照文中的方法进行了处理。具体实现位于 KeyStoreHelper.java,参考了 github 上某位作者的代码。

  7. 发布应用和 bug 收集

    一开始用的是之前一直用的 fir.im 和 bugHD,最近发现 fir.im 很久没更新了,于是切换到了 蒲公英 ,包含了应用下载、更新、bug 收集、意见反馈等功能,挺好用的。