December 11th, 2016
Android Weekly Issue #235
本期内容包括: 开发一个自定义View并发布为开源库的完整流程介绍; 用AnimatedVectorDrawable
实现的动画; 什么样的程序是可测试的; DownloadManager
介绍; Okhttp的重试; Android 7取消了file://
; Android Studio即将推出的build cache功能; 支持离线模式的app构架; 如何写自定义的lint规则; Epoxy, 一个处理复杂RecyclerView屏的库; FragmentPagerAdapter
和FragmentStatePagerAdapter
的比较等.html
做者开发了一个环形的SeekBar, 并把它做为一个库发布到了JCenter.java
做者首先讲了自定义View的实现:
首先是关于View生命周期的介绍, 在写自定义View的时候有几个关键的生命周期回调须要处理:
android
做者实现的几个关键步骤讲解:git
onMeasure()
中控制尺寸.onDraw()
中绘制: 避免在onDraw()
中分配内存; 用invalidate()
方法来激发重绘.onTouchEvent()
处理用户手势. 在他的环形SeekBar的实现里, 这里涉及到了点击坐标到角度的转换.将自定义View库开源到Github:
开源到Github有个好的README很重要, 这里有几个tips:github
发布库:api
用AnimatedVectorDrawable
实现的一个很fancy的位置标志动画.android-studio
若是程序的架构不适合测试, 那么硬要写一些测试极可能就会面临这样的局面: 要么就是发现无法写测试, 要么就是为了写测试而破坏了代码, 作了一些奇怪的事情.缓存
那么究竟是什么样的程序才是适合写测试, 或者是可测试的呢?cookie
有一个有趣的定义是seam(接缝), 在接缝处你能够改变程序的行为, 而不用编辑当前程序. 若是程序没有接缝, 你将没法设置测试的初始条件和验证测试结果.网络
本文中举了一个实际的例子, 开始的时候程序没有seam, 因此致使没法测试, 后来把静态方法改成实例的方法以后, 咱们就能够经过Mockito来模拟行为, 设置条件, 最后经过验证某一方法的调用与否来进行验证.
用DownloadManager
来处理下载.
首先它在设备上有本身的UI, 还有notification, 还有Downloads app能让用户管理下载文件.
咱们能够查询到文件的一些信息, 好比MIME type, 文件尺寸, 下载状态等.
咱们还能够用getUriForDownloadedFile()
方法来获取一个URI, 配合MIME type, 发送Intent, 来打开一个相关的查看程序.
关于储存文件的合适地点:
setDestinationInExternalFilesDir()
.WRITE_EXTERNAL_STORAGE
权限. setDestinationInExternalPublicDir()
.在网路较慢或不稳定的时候, OkHttp有可能会重复发送请求, 直到成功.
这个重试的逻辑是经过RetryAndFollowUpInterceptor.java实现的.
那么, 咱们能够关掉这个重试行为吗? 有一些issues就在讨论这个问题: Issue # 1043. 后来有两个pull requests: PR #1259和PR #2479改进了这个问题, 减小(但并无消除)了没必要要的retry请求.
全局关闭重试行为: OkHttpClient.Builder .retryOnConnectionFailure()
设置为false. 可是注意这样是很粗暴并具备破坏性的, 消除了retry逻辑带来的好处:
解决真正的问题: 关闭静默重试在某些情形下有帮助, 可是其实它隐藏了真正的问题, 就是你的API是不是幂等的idempotent. server端能够根据客户端的GUID来检测重复, 这样server就不会屡次执行操做, 会通知发送者.
Android N (Nougat, API 24)开始, 再也不容许发送file://
的Intent, 将会直接抛出FileUriExposedException
异常.
因此当你把targetSdkVersion
改成24以后, 你必需要确保你修复了这些问题再发布.
解决方案是什么呢? 用content://
, 结合FileProvider
:
首先在manifest里面声明:
<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/> </provider>
而后在res\xml\provider_paths.xml
文件里指明路径:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="."/> </paths>
最后, 把
Uri photoURI = Uri.fromFile(createImageFile());
改成
Uri photoURI = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", createImageFile());
而后放在Intent里发送就行了.
注意, 若是你的targetSdkVersion
尚未更新到24, 那么即使是在Nougat的手机上file://
也仍然是能正常使用的.
Android Studio当前的最新版是2.3 Canary 2. 有一些新的改进, 可是其中最吸引人的是这个build cache. 它会使你的clean build更快.
本文后面解析了build cache的工做原理.
一个好的应用应该在网络很差甚至离线的时候仍然可使用, 咱们应该作些什么呢?
如何建立自定义的lint规则.
事情的由来是做者发现了一个死循环调用, 而后他想作一个什么标记以防之后其余人会犯一样的错误.
而后他想到的是@Nullable注解, 的检查, 实质是依靠lint来实现的.
因而他本身写了一个自定义的lint规则, 来提示使用用他的注解@CarefulNow
标记的方法时应当注意.
详细的实现方式请看原文.
epoxy是一个Android库, 用来处理复杂的RecyclerView屏. 本文介绍了它在项目中实际的使用.
可能有不少Android开发者对于
FragmentPagerAdapter和FragmentStatePagerAdapter的区别不是太清楚或根本不知道, 本文做者就具体介绍了两者的不一样.
基本不一样
FragmentPagerAdapter
适用于项目个数肯定的情形.
为何呢? 由于一旦fragment的实例被建立, 它永远也不会从FragmentManager
中移除, 直到Activity被销毁.
当Fragment不见的时候, 仅仅是onDestroyView()
被调用, 当fragment再次回来时, 再调用onCreateView()
.
FragmentStatePagerAdapter
当fragment的实例不可达的时候, 实例就会当即从FragmentManager
移除. 被移除的fragment实例的状态由FragmentStatePagerAdapter
保存, 当你再次回到该项的时候, fragment会重建新实例, 而且状态被恢复. 因此这种adapter适用于项目个数不肯定或的状况.
因此使用FragmentPagerAdapter
的时候须要注意内存问题.
notifyDatasetChanged()的问题.
notifyDataSetChanged()
是用来处理数据集变化的状况, 好比一些项目增删的状况. 这个方法不是用来刷新当前显示的Fragment或其中的Views的.
文章中还有一些关于数据改变实现以及现有issue的讨论. 为了解决issue做者还发布了一个库UpdatableFragmentStatePagerAdapter.
一个quick settings tile来开启"Don't keep activities".
一个波形的loading图, 水面上涨表明loading程度.
Simple MVWhatever for Android.
一个处理复杂的RecyclerView屏的库.
录屏脚本.