博文

目前显示的是 四月, 2014的博文

Android 实现模糊效果的一些笔记

不知从 ios 的那个版本起有了毛玻璃效果,于是这东西就成了 Android UI 设计师们爱用的效果之一。实现这个效果,技术的核心是对图像的模糊处理。

当然,技术上需要做到什么程度,取决于要实现的效果如何。如果需要模糊的对象是固定的,而且是整个图像一起模糊掉,那么最简单的办法还是在开发阶段就计算好模糊的图片——photoshop 的滤镜能达到的效果永远比工程师重复发明轮子在用户手机上算要来的好。然后把这模糊图放在清晰图的上面,通过控制模糊图 ImageView 的透明度来实现渐变毛玻璃效果。在布局不是特别复杂的情况下,这样做的效率还可以接受(实在想优化的话就自己在 Canvas 上画吧)。

如果需要在手机端计算模糊图,那么这篇文章这篇文章是很好的补习资料,常见的 Box blur 和 Gaussian blur 的原理讲的很清楚。实际上,Gaussian blur 因为涉及的基本都是浮点计算,执行时间是 Box blur 的数倍。以 note2 为例,自行计算一张 radius=16 的 720x1280 的 Gaussian blur 图片,Java 版本需要约 1 分钟,c++ 版本最快也要约 20 秒(纯 cpu 单线程,多线程的边界情况处理器来很麻烦所以没折腾成),而 Box blur 同样的图片虽然可以在几秒内完成,但对于某类图片(比如带明显横竖条纹的)的模糊效果非常差,即使两次 Box blur 出来的效果也还是差强人意。自行实现模糊的另一个要命的问题是内存。例如 StackOverflow 的这个 FastBlur 答案(很多讲模糊文章都引用了这个答案),虽然速度上还不错,但是内存消耗的实在是有点粗放,只适合做小图片处理。

据说 API 17 以上 Android 提供了 RenderScript 来可以利用 GPU 做模糊计算。去年底的时候我参考这篇折腾过,不过没成功。一是 API 17 这个门槛实在是高(貌似通过 android-support-v8 也可以,但也非常折腾),二是 RenderScript 调试起来实在困难。总之 RenderScript 这条路我没走通。前阵子又有一篇文章带了示例代码,有兴趣的同学可以继续尝试。需要注意的是像这种高大上的解决方案,兼容性有待验证(Android 设备的又一个命门)。但是这篇文章末尾提到的先 s…

Android 应用卸载监控的实现方法

不再主业折腾 Android 了,这段时间会陆续把之前折腾过的东西记录一下,免得日后忘记。

对于产品经理和运营来说,知道哪个用户,什么时候,为什么会卸载你的 app 可能是很重要的事。虽然我觉得挺扯蛋——看看国内那些应用在卸载时弹出的页面,可选原因 12345,列的比用户想的都全面周到——这分明就是在说,我也知道自己干了很多坏事让你们不爽,可我干的坏事是如此之多以至于我实在弄不清你们的底线在哪里。

好吧,在我朝可以有理想,但是不能太理想主义。所以本文只从技术角度讨论一些实现细节。

首先来看这篇文章,基本勾勒出了实现卸载监控所需的技术框架。这篇文章有以下几个关键字:

JNI
Android 应用被卸载之前,其运行实例就会被停止掉。因此必须要有代码能够脱离应用的生命周期管理。这个入口就是 JNI。进入 c 的世界,想象空间完全不是 Android API 可以比拟。fork
对于卸载监控这个需求来说,JNI 是入口,为的就是进入 fork 这一环。fork 本身是比 Java 更为历史悠久的系统调用,在这里负责生成监控进程,是整个逻辑中非常关键的一环。至少要把 fork 示例的执行逻辑搞懂(系统补习的话当然是建议读 APUE 相关章节,后面 exec 也会用到)。inotify
Linux 特有的文件监控 api,IBM 这篇介绍的很好。UserSerial
这个是 Android 4.2+ 引入的安全机制,原文说的很清楚,这里不再赘述。 但是这篇文章的实现方案两个明显不足: fork 出来的进程仍旧是一个带着 dalvik 的庞大进程(内存 20MiB+)通过进程父子关系较容易找到卸载监控进程 所以,针对上述不足,可以继续改良实现方案: exec
将 inotify 部分的逻辑抽离到独立的可执行文件中,fork 出来的监控进程,可以通过 exec 这个独立的可执行文件来将自己变成一个非常轻量级的监控进程(内存占用只有 KiB 级别),同时也可以通过参数将伪装自己的进程名字。其实 fork + exec 的组合在传统的 unix 多进程编程中非常常见。两次 fork
为了断绝父子进程关系,可以通过两次 fork 的技巧。主进程 A 通过 JNI 调用,进行第一次 fork,其父进程 A 继续运行,子进程 B 调用 exec 成为监控进程。监控进程 B 再进行一次 fork,父进程 B …