技术和感悟分享
来阿里实习这些天来,学到了很多东西,尤其是Android开发方面,两个月前还觉得难以实现的需求,现在也都能尝试着写出来了,感觉对Android开发的胆子越来越大了,什么都敢去尝试。
技术分享
先来和大家分享在技术方面的一些收获吧。
实习以来,我做的工作主要是下面这些:
- 机型适配和bug修复
- 动效的实现
- 一些小的UI需求的实现
第三点太杂太碎,我就从前两点开始讲吧。
1. 适配和Bug修复
因字号引起的适配问题
这可能是在UI方面可能会产生的比较严重适配问题 如图,这是在中兴U985、酷派7295上显示的一个界面,这两款手机经常会从测试工程师那里接到各式各样的适配问题。
我仔细对照了一番XML和手机的显示,发现布局文件的尺寸写的都没有问题,按照常理来说无论多小屏幕的手机都不会出现图中的情况。
后来我用手比划着量了一下尺寸,忽然明白了问题的根源——这两款手机的字号比普通的手机字号要大!
我去设置里一看,再和其他手机一对比,这两个手机的普通的字号==其他手机的大字号,而它的小字号才是正常手机该有的字号。在这个俩手机上1sp!=1dp
这样一来在这些手机上,文字的部分因为字号用的是sp,随着更大的系统字号占据更大的空间。
我的解决方案就是,如果你发现布局是这种情况,注意一下,因为UED给的标注稿可能是恰好计算好的,这时候字号一旦变大,必然会挤出去。所以要先保证上下间距,在此基础之上把布局整体的高度变成最小高度。
当然,除了这个办法之外,还有一个猥琐的方法,在baseActivity或者baseApplication里重载:
1 |
|
强制使app的字号按照1sp=1dp,不跟随系统。(当然已经有前人加过了)
这个是一个很容易遇到的适配问题,中兴酷派好像比较喜欢大字号(他们更猥琐)。(可能是做出的手机分辨率低,用大字号撑起来,显得界面元素不是很小,跟老人机一样。)
参考链接:http://blog.csdn.net/yinkai1205/article/details/34423711
Android4.0/4.1 RootView 的Background变黑的问题
这个也是经常会碰到的(如图)。
原来应该白色的背景,变成了黑色,原因就是rootview的background用的是@color/white,或者selector 用@color/white。这个问题只有在rootview上用@color做背景颜色,而且4.0/4.1上才会出现。
这个我在stackoverflow找到的解决方案就是: 用@drawable一个白色的小像素的图片代替。(我看资源文件里已经有这个图片了,可能以前有人碰到过,就是用这种方法解决的)
或者自定义一个drawable内容是:
1 | "1.0" encoding="utf-8" xml version= |
Android5.0的BackgroundDrawable问题
1 | view.getBackground().setAlpha(0); |
这行代码看起来没有任何问题,但是在Android5.0上,一旦你这样设置某个view的background的透明度。所有的view,所有的view的透明度都会变成你设置的这个值,简直就是不可思议。
最后在stackoverflow上找到答案,就是Android5.0做了某种优化,使得每个view都共享同一个ColorDrawable。所以以后再碰到对view的background做改变的时候就要注意了。涉及颜色的都会有同样的问题。
解决方法也很容易,加一个mutate()就好:
1 | view.getBackground().mutate().setAlpha(0); |
原理就不说了,才疏学浅说不清楚,可以直接看以下的链接:
ScrollView的fillViewport属性
比如你想实现一个Tab,或者其他什么东西。总之要内容不足的时候均摊显示,内容超出的时候可以向左滑动,显示右边没显示出来的内容。
这个时候不要想着去怎么计算,怎么获取控件的长宽,然后除以n。都不用,只用把里面的LinearLayout的每个子view的weight设置为1了,然后呢?LinearLayout在ScrollView里面只能warp_content呀?
这时候,只需要将ScrollView的fillViewport属性置为true,这样当LinearLayout长度不足时,自动会变成match_content,这样里面的view就均摊了。
小技巧,很受用。
2. 动效
Property Animation VS Tweened Animation
Tweened 动画:
- 只有4种类型 平移(Translate)、旋转(Rotate)、缩放(Scale)、透明度(Alpha)。
- 只是显示的位置发生改变,实际的控件没有改变包括事件。
Property 动画:
- view所有的属性变化都能当做动画
- view实际变化而不只是显示变化
总结:
- Tweened适合做临时的,不影响后续动作的。(转场动画、播放动画)
- Property适合做用户使用路径上的动画。(隐藏标题栏、点击滑动特效)
- 用Property更为保险,因为它是真真切切地改变了view。
- 经过少量的对比Property和Tweened的性能基本是一样的,不存在谁的性能要差一些。
- Tweened有的四种类型Property都有,而Property的背景颜色改变、不拉伸、不虚化都是Tweened没有的。
- Property结合各种
Evaluators
可以做到很方便地控制动画的每个过程
性能优化
我在做一个气球动画的时候,出现了动画卡顿的情况,当时就刚好研究了一下Android动画的性能优化。
我们都知道,Android为了能达到流畅的视觉效果需要的60fps,是每16ms发送一次VSYNC信号,来触发UI的渲染。
而如果有耗时的操作使得这16毫秒延后被执行draw的话,就会出现掉帧的现象。
怎么具体分析掉帧的原因呢?常用的手段就是用adb的一个工具:
adb shell dumpsys gfxinfo com.xxxx.xxx
它会导出一个三列的数据表:
把这三列数据在Excel中绘制成一个累积条形图,就可以清晰看到了:
当然,还有个更方便的办法,就是直接在开发者选项里,有个“GPU呈现模式分析”:
打开之后在屏幕底端就会出现这个,其中绿色的那条线就是16ms的界限,超出去的就是掉帧的地方。
- Draw:表示在Java中创建显示列表部分中,OnDraw()方法占用的时间。
- Process:表示渲染引擎执行显示列表所花的时间,view越多,时间就越长。
- Execute:表示把一帧数据发送到屏幕上排版显示实际花费的时间。
简洁地说就是:
- Draw: 在UI线程里操作过多
- Process: View过多,一般来说,去检查过度嵌套和重绘
- Execute: 所需时间很少,一般可以忽略
上图就是我导出的气球动画执行时的GPU数据。可以看出因为气球很多,所以Process占了很大比例,同时因为气球背景是首页的各种数据正在加载,还有banner的动画,所以有些帧的Draw也很高。
后来减少了气球布局文件的layout层数,果然动画变流畅了不少。
气球这个是Process耗时的案例,下面讲一个Draw耗时的案例。
这是个轮播的banner,它的背景是一个前面这个卡片的50px半径的高斯模糊,如图:
这个轮播动画的时候会掉帧,就是这个卡片瞬间就跳到下一张去了,根本看不到滚动中间的动画。
这个动画的优化,因为这个效果必须要用这么多层堆上去,所以想减少view来提高性能很难。
后来测了一下时间发现,在UI线程里做高斯模糊使得UI线程阻塞了。阻塞了多久呢?100毫秒左右。其实100毫秒不算很长,为什么说不长呢?你点一下鼠标,这一张ppt延迟了100毫秒才切换到下一张,你会有明显的感知吗?不会的,不会觉得这很不爽。但是这100毫秒刚好在16毫秒更新UI的时候延时,这时你肯定会觉得很卡,因为它在连续不断地停顿。
所以针对这种问题,怎么解决呢?很简单,也很老套——开线程,把高斯模糊的处理放到线程里,处理结束,再更新UI,让卡片动画先滚动过来,再把背景更新成下一张。这样,把100毫秒放到动画以外,用户就基本不会察觉到这个延迟,也不会因为这个延迟感到不适。
同理,在做很多动效的时候我都遇到类似的问题,基本都是通过类似的方式解决的。先保证动画流畅执行,数据加载、其他UI更新,可以暂缓。
参考链接:http://hukai.me/android-performance-patterns/
视觉特技
这个动画想实现的效果,是Material Design提倡的一种动画,叫“有意义的转场动画”。就是说,用户从一个activity跳转到另一个activity的时候,有一个不变的元素A,通过这个不变的元素建立两个界面之间的连接。
对于这种动画,怎么实现呢?首先你不能用补间动画,因为用补间动画是粗暴的拉伸,图片,包括上面字都会被拉丑。如果在Android5.0上,有一些库可以实现activity之间的这种过度,但是对于5.0以下,还是用悬浮窗大法,打一个时间差。
过程如下:
- 在点击View的瞬间,添加一个透明背景的全屏悬浮窗。
- 在这个悬浮窗上复制一个这个view的副本,并隐藏旧view。
- 在悬浮窗上执行动画。
- 动画执行到某个时间点时启动下一个Activity。
- Activity完全加载好后,隐藏悬浮窗,并恢复旧的view。
我这里直接继承了气球的悬浮窗的,写了个AnimationFloatView
。然后又封装了一个ViewChangeAnimation
的类。放到library库里了,以后如果需要实现相似的动画效果,可以直接取用。
它的入参是这样的:
你可能觉得这好麻烦的初始化,为什么只传递旧view还不够呢?还要旧view的单独的layout的id?
因为在Android中View对象不能深拷贝!!
view对象只能用inflate
从xml中加载!
所以你可以选择inflate好一个新view传递给我,或者给我一个layout的id,我在类内部自己拷贝。
然后设置好view结束时候的长宽和坐标:
最后再设置一下动画的时长啊、差值器啊、延时之类的,start()一下,就能帮助你无缝把一个view动画传送出去了。
最后的效果就是这样:
感悟分享
感悟比较抽象,我就简单一点说吧。
代码架构
这个是我今年1月份写的,左边这张图是封装的是一个一个的HTTP请求的类,每个类对应的是右边是写的服务端提供的API。
对于每个服务端的API我都要写一个接口文档,对于每一个API的请求都要手打一个JavaBean+Net类。当时写这两部分简直就是噩梦一般。客户端代码耦合度非常高,出问题几率大,改动又麻烦。
来阿里实习之后发现了Mtop平台,简直要亮瞎我了。世间竟有如此方便的平台,还能直接下载json和POJO。而且客户端的请求也写的非常漂亮,耦合度很低,很方便。
还有其他的很多代码架构,感觉比较规范,其中还有ROC的数据绑定,然后大概了解了一下MVVM模式,感觉收获很多,对网络部分的架构也有了新的的认识和见解。
(受到了启示,准备自己写一个网络框架,带本地缓存的带服务端文档的。)
探讨学习
来实习给我感受比较大的就是有一个特别好的氛围,可以和同事一起对某个技术难点某个bug一起讨论。而且还有很多大神可以请教,不会有那种自己一个人死扣,很无助的感觉。
再者就是可以有一个相对宽松,不浮躁的环境,可以有时间对某个问题仔细研究探讨。以前做项目一般都比较赶,很多东西都是不求甚解的,要赶deadline,所以没有时间去追个所以然,只要实现结果就可以了。
(也可能是因为我是实习生的缘故吧,我感觉除了要发布这几天,其他时候给我的时间还是蛮宽松的。)
团队协作
最后,给我感触比较大的,就是团队协作了。也通过这些天,认识了一些产品经理、UED、测试工程师。让我亲眼目睹了整个项目的工作流程。
工作有时候要不停地和UED去checkUI,要和测试工程师了解bug细节……感觉真正体会到了整个大团队日常运转的过程,感觉很有意思。也特别值得思考。
思考如何去高效的和人沟通,怎么把自己的意图传达给别人。我在这方面还是比较欠缺的,有时候比较羞涩,不太敢于主动找人沟通,实习这段时间也在慢慢锻炼,感觉还是有些提升的。
总结
不总结了,谢谢大家