【阿里实习】技术和感悟分享

技术和感悟分享

来阿里实习这些天来,学到了很多东西,尤其是Android开发方面,两个月前还觉得难以实现的需求,现在也都能尝试着写出来了,感觉对Android开发的胆子越来越大了,什么都敢去尝试。

技术分享

先来和大家分享在技术方面的一些收获吧。

实习以来,我做的工作主要是下面这些:

  • 机型适配和bug修复
  • 动效的实现
  • 一些小的UI需求的实现

第三点太杂太碎,我就从前两点开始讲吧。

1. 适配和Bug修复

因字号引起的适配问题

这可能是在UI方面可能会产生的比较严重适配问题 如图,这是在中兴U985、酷派7295上显示的一个界面,这两款手机经常会从测试工程师那里接到各式各样的适配问题。

我仔细对照了一番XML和手机的显示,发现布局文件的尺寸写的都没有问题,按照常理来说无论多小屏幕的手机都不会出现图中的情况。

后来我用手比划着量了一下尺寸,忽然明白了问题的根源——这两款手机的字号比普通的手机字号要大!

我去设置里一看,再和其他手机一对比,这两个手机的普通的字号==其他手机的大字号,而它的小字号才是正常手机该有的字号。在这个俩手机上1sp!=1dp

这样一来在这些手机上,文字的部分因为字号用的是sp,随着更大的系统字号占据更大的空间。

我的解决方案就是,如果你发现布局是这种情况,注意一下,因为UED给的标注稿可能是恰好计算好的,这时候字号一旦变大,必然会挤出去。所以要先保证上下间距,在此基础之上把布局整体的高度变成最小高度。

当然,除了这个办法之外,还有一个猥琐的方法,在baseActivity或者baseApplication里重载:

1
2
3
4
5
6
7
8
9
10
11

@Override
public Resources getResources() {
Resources res = super.getResources();
Configuration config=res.getConfiguration();
if(config.fontScale != 1){
config.fontScale =1;
res.updateConfiguration(config,res.getDisplayMetrics() );
}
return res;
}

强制使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
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<resources>
<drawable name="semitransparent_white">#ffffff</drawable>
</resources>

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);

原理就不说了,才疏学浅说不清楚,可以直接看以下的链接:

参考链接:“http://stackoverflow.com/questions/27115181/button-with-getbackground-setalpha-on-version-5-lollipop-isnt-working-corre”

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 动画:

  1. 只有4种类型 平移(Translate)、旋转(Rotate)、缩放(Scale)、透明度(Alpha)。
  2. 只是显示的位置发生改变,实际的控件没有改变包括事件。

Property 动画:

  1. view所有的属性变化都能当做动画
  2. view实际变化而不只是显示变化

总结:

  1. Tweened适合做临时的,不影响后续动作的。(转场动画、播放动画)
  2. Property适合做用户使用路径上的动画。(隐藏标题栏、点击滑动特效)
  3. 用Property更为保险,因为它是真真切切地改变了view。
  4. 经过少量的对比Property和Tweened的性能基本是一样的,不存在谁的性能要差一些。
  5. Tweened有的四种类型Property都有,而Property的背景颜色改变、不拉伸、不虚化都是Tweened没有的。
  6. 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以下,还是用悬浮窗大法,打一个时间差。

过程如下:

  1. 在点击View的瞬间,添加一个透明背景的全屏悬浮窗。
  2. 在这个悬浮窗上复制一个这个view的副本,并隐藏旧view。
  3. 在悬浮窗上执行动画。
  4. 动画执行到某个时间点时启动下一个Activity。
  5. 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细节……感觉真正体会到了整个大团队日常运转的过程,感觉很有意思。也特别值得思考。

思考如何去高效的和人沟通,怎么把自己的意图传达给别人。我在这方面还是比较欠缺的,有时候比较羞涩,不太敢于主动找人沟通,实习这段时间也在慢慢锻炼,感觉还是有些提升的。

总结

不总结了,谢谢大家