他一些永久、临时的缓存。当下不少应用会把 webview 放在另一个进程中打开以避免内存泄漏,但是他们 cookies 的设置往往还是在主进程中,所以开发者需要仔细排查自己的应用是否有这么使用,webview 相关运行是否正常等。
4.3 com.android.internal 包下某些类找不到
升级到 28 之后,应用编译后抛出 com.android.internal
包下面有些类找不到的异常,经过查找发现这些类已经从 SDK 中移除。针对这种情况目前有两种处理办法:
- 移除该类的调用逻辑;
- 在应用中新建一个同名类,将被移除类的所有代码逻辑复制到新建类中(必要时可能需要将被移除类相关类同时拷贝一份到应用中),然后将应用中所有相关 import 引用直接修改成新建类的包名引用即可;
下篇:Android P 实用新特性
Android P 这次当然也有很多丰富的特性,总结了两个对于第三方应用开发者比较实用的特性
。
一、HEIF 图片格式支持
HEIF(High Efficiency Image Format),高帧率图片格式,采用的是 HEVC 编码格式。苹果于 iOS11 版本开始支持该图片格式,而 Android 则是在 Android O MR1 版本开始支持 HEIF 静态图的软解码,在 P 版本上完全支持该格式的软编解码。HEIF 格式的压缩率是 JPEG 的 2.39 倍,同等大小质量的图片可节省 50% 的空间和网络传输流量,而且支持动图。HEIF 格式比起 GIF 格式来说有着更好的图片展示效果,所以 HEIF 格式图片的目标是用来代替 JPEG 成为主流的图片压缩格式。HEIF 格式图片的扩展名为 .heif 或者 .heic:
最大尺寸 |
无上限 |
16383x16383 |
65535x65535 |
编码 |
HEVC |
VP8 |
JPEG |
是否支持其他编码 |
YES |
NO |
NO |
支持音频/文字 |
YES |
NO |
NO |
支持多图片 |
YES |
YES |
NO |
支持裁剪 |
YES |
NO |
NO |
支持透明 |
YES |
YES |
NO |
支持缩略图 |
YES |
NO |
YES |
分块加载 |
YES |
NO |
NO |
看上去很美好,但是目前还不是所有的 Android P 机型都会支持 HEIF 格式硬编解码,因为这需要特殊的硬件支持同时还需要缴纳一定的专利费,所以在编解码效率上就会有机型差异,同时 Android P 软编解码也只能支持静态 HEIF 格式图片。目前开发者可以通过版本来判断是否支持 HEIF 编解码,判断逻辑如下:
fun supportHEIF() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
解码代码也很简单,支持将 HEIF 格式图片解码成 Bitmap 和 Drawable:
@TargetApi(28)
fun decodeHEIFDrawable(filePath: String): Drawable? {
if (!supportHEIF()) {
return null
}
var source: ImageDecoder.Source = ImageDecoder.createSource(File(filePath))
return ImageDecoder.decodeDrawable(source)
}
@RequiresApi(28)
fun decodeHEIFBitmap(filePath: String): Bitmap? {
if (!supportHEIF()) {
return null
}
var source: ImageDecoder.Source = ImageDecoder.createSource(File(filePath))
return ImageDecoder.decodeBitmap(source)
}
另外扫描本地图片则继续使用 ContentResolver 即可,如果设备支持 HEIF 格式,系统会自动扫描上 HEIF 格式的图片:
var cursor : Cursor = getContext().getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null)
但是这样还远远没有适配完成,第三方应用适配 HEIF 格式图片有一个很困难的地方是本地虽然可以识别解码 HEIF 格式的图片,但是如果某个用户将其设置为头像上传到后台,后台将其下发给其他不支持 HEIF 图片格式解码的手机,这些手机就肯定有展示问题。解决这个问题目前有两种思路:
- 终端在上传之前将其转码成 JPEG 格式的图片,但是这样就根本没有充分利用到 HEIF 图片的高压缩率的优势;
- 在到达后端之后,后端将其转码成 JPEG 图片,同时保存一份 HEIF 和 JEPG,到时候根据用户是否可以解码 HEIF 下发不同格式图片。该方案可以充分利用 HEIF 的优点,但是大大增加了后端存储空间和开发工作量。
二、ImageDecoder
上面已经介绍到了 ImageDecoder
在解码 HEIF 图片中的应用,但是实际它的功能完全不仅于此,在 Android P 中它可以完全替代 BitmapFactory
和 BitmapFactory.Options
相关类。ImageDocoder
类可以通过字节数据、文件和 URI 来解码一张图片。用法和之前一样,首先通过 createSource
方法创建一个图片文件的 ImageDecoder.Source
对象,然后调用 decodeDrawable
或者 decodeBitmap
方法传入之前的 ImageDecoder.Source
对象就能生成图片的 Drawable 或者 Bitmap 对象引用。ImageDecoder
支持 PNG、JPEG、WEBP、GIF 和 HEIF 多种格式图片的解码,另外解码 GIF 或者 WEBP 格式图片得到的是一个 AnimatedImageDrawable
对象,AnimatedImageDrawable
类的工作原理和 AnimatedVectorDrawable
类似,都是使用一个工作线程来解码,所以解码线程和显示线程互不干扰。AnimatedImageDrawable
用法也很简单:
var drawable: Drawable = ImageDecoder.decodeDrawable(source);
if (drawable is AnimatedImageDrawable){
image.setImageDrawable(drawable)
drawable.start()
}
ImageDecoder
除了基础的解码功能之外,还有很多非常实用的方法,比如通过设置 OnHeaderDecodedListener
就可以在解析图片之前获取到图片的宽高等信息,同时还可以根据需要设置采样率:
val listener = object : OnHeaderDecodedListener {
fun onHeaderDecoded(decoder: ImageDecoder, info: ImageInfo, source: Source) {
decoder.setTargetSampleSize(2)
}
}
val drawable = ImageDecoder.decodeDrawable(sou