Android Weekly Issue #247
March 5th, 2017
Android Weekly Issue #247.
本期内容包括: 离线模式的实现; RxJava2的测试支持; MVI模式中的单向数据流; FlexboxLayout的使用; 用脚本来配置项目的版本名和版本号; Fragment的转场动画; MVP模式的几点原则;
RxJava中需要注意的一些点; RxJava在Android中的实现例子; JUnit 5使用.
ARTICLES & TUTORIALS
Offline support: “Try again, later”, no more
作者他们的应用很好地处理了离线模式, 他们的基本原则是, 应用中不需要显示任何的loading控件.
在离线装填下, 在用户看来仍是可以提交请求的, 只不过出现了一个sync的小图标, 一旦当用户再次连上网络, 他的请求就会被发送出去.
然后作者讲了他们的程序设计:
首先是MVP结构, 使用了Content Provider包装的SQLite数据库. (此处列举了使用Content Provider的若干优点).
后台的同步工作, 他们选择了GCMNetworkManager
.
基本流程是这样: 但用户提交请求, 首先存储在数据库中, 状态为pending, 然后后台service发送请求, 如果成功, 则更新数据库中的状态为synced; 如果失败, 则用GcmNetworkManager
schedule一个task, 在网络连接恢复时再做一次尝试, 成功和失败的处理同上一步.
Story Code
作者讲了一种方法, 以一种叙事的方式来写一个测试故事, 然后把它分成很多个小的测试cases. 这样可以用来驱动API的设计和其实现等.
Testing RxJava2
本文介绍RxJava2中内置的关于测试的支持.
测试一个Observable
可以用TestObserver
; 测试Flowable
可以用TestSubscriber
.
如何测试在不同线程上的工作?
有几种选择:
- 把Observable变为blocking的. ->
blockingIterable()
, 缺点: 测试慢. - 强制测试等待, 直到某个条件达成. ->
awaitTerminalEvent()
. 此处还推荐一个库: awaitility. - 把schedular换为一个immediate的.
RxJavaPlugins.setComputationSchedulerHandler(scheduler -> Schedulers.trampoline());
. 需要最后reset一下, 可以用JUnit的TestRule来进行简化.
用TestScheduler
可以操纵时间, 进行白盒测试.
利用它在测试中可以精确控制时间过去了多少, 我们可以测试在中间的时间点的状态.
值得注意的是它控制的并不是真实的时间, 真实的时间还是立即就度过了的, 所以不会降低测试的速度.
我们也可以利用TestRule
和RxJavaPlugins
来把这个scheduler设置为测试时候要切换成的scheduler.
Syncing Changes
Trello的离线模式实现文章系列之二. 基本的原则是在离线的时候把改动(deltas)存在数据库里, 之后有机会再同步给server.
本文介绍了他们如何计算delta和将它们按时间上传到服务器.
Reactive Apps With MVI - Part 4
MVI系列文章的第四篇. 本篇讲如何构建独立的UI单元.
作者认为Presenter之间的Parent-Child关系是一种code smell, 因为这样引入了一种强耦合的关系, 不好读, 不好维护.
你也许要问那Presenter之间如何通信呢? 答案是, 它们根本就不需要通信, 它们只需要更新和观测同一个Model(可以说业务逻辑), 让底层来通知它们事件的发生就可以了.
Resources for Learning how to Test Android Apps
关于Android测试的相关资源分享.
Unboxing the FlexboxLayout
作者想实现一个动态关键字的流式布局, 可以根据parent的宽度自动换行.
他想了几种方法, 都不太合适, 所以最后选择了FlexboxLayout
.
作者尝试了单独使用FlexboxLayout
和 将FlexboxLayoutManager()
设置为RecyclerView
的Layout Manager两种办法来实现他想要的效果.
Configuring Android Project - Version Name & Code
首先介绍了git-describe命令.
git describe -tags
可以输出当前最近的tag和它之后有几个提交, 还有最新提交的hash.
作者建议使用这个库: grgit, 写一个script-git-version.gradle:
1 | buildscript { |
在主文件中apply这个文件.
执行printVersion task后会输出类似这样的信息:
1 | Version Name: 1.0-2-gdca226a |
这样使用:1
2
3
4
5
6
7
8
9
10
11productFlavors {
dev {
versionCode gitVersionCodeTime
versionName gitVersionName
}
prod {
versionCode gitVersionCode
versionName gitVersionName
}
}
这样就自动生成了版本号和版本名.
你还可以进一步设计, 在版本名中包括分支名, 时间戳之类的.
Workcation App - Part 1. Fragment custom transition
作者的系列文章, 讨论他的项目中的动画的实现.
本文是第一篇, 介绍进入map的转场动画.
首先, 在map加载完毕后, 存一个截图放在缓存里, 然后用一个自定义的Transition来做缩放和渐变的动画, 最后把它设置为fragment的转场动画.
Model-View-Presenter: Android guidelines
MVP实现的一些guidelines和最佳实践.
- 1.View要无脑和被动.
- 2.Presenter要和framework无关, 不依赖任何Android的类.
- 3.写一个协议描述View和Presenter的交互.
- 4.定义命名规则来区分职责.
- 5.不要在Presenter里创建生命周期的回调方法.
- 6.Presenter和View是一对一的关系. 可以定义
attach()
和detach()
或start()
和stop()
来关联和解除关联. - 7.不要在Presenter里用Bundle保存状态. 因为不能包含Android的类.
- 8.不要保存Presenter. 因为Presenter并不是一个数据类.
- 9.在Model中提供cache来恢复View的状态.
5 Not So Obvious Things About RxJava
RxJava使用学习中的五点(RxJava1.2.6).
- 什么时候用
map()
或者flatMap()
. - 不使用
Observable.create()
来创建observables. 使用其他更方便的方法, 比如syncOnSubscribe
,fromCallable
,fromEmitter
. - 如何处理Backpressure.
- 如和能让流不因为errors而停下来.
- 如何分享Observable到多个订阅者 ->
share()
或publish()
.
Simplify Concurrency with Reactive Modelling on Android
用RxJava来处理Android上的并发和异步.
作者的文章中举了很详尽的各种例子.
JUnit 5: Getting Started
使用JUnit 5做测试.
本文讲了一些在Android上setup可能会遇到的问题及怎么解决.
LIBRARIES & CODE
FastHub
一个Android的Github客户端.
gradle-android-javafmt-plugin
一个gradle plugin, 自动format代码.
HtmlCompat
Android中Html类的兼容库.