Long Luo's Life Notes

每一天都是奇迹

翻译By Long Luo

原文链接:Performance Tips for Android’s ListView

译者注:
1. 由于这是技术文章,所以有些词句使用原文,表达更准确。
2. 由于水平有效,有些地方可能翻译的不够准确,如有不当之处,敬请批评指正;
3. inflation这个词一直找不到特别好的中文翻译。

ListView如何运作的?

ListView是设计应用于对可扩展性和高性能要求的地方。实际上,这就意味着ListView有以下2个要求:

  1. 尽可能少的创建View;
  2. 只是绘制和布局在屏幕上可见的子View。

理解第一点很简单:通过布局xml文件在创建View并显示是很昂贵耗时耗资源的操作。尽管布局文件已经编译打包成了二进制形式以便于更高效的语法解析,但是创建View仍然需要通过一个特殊的XML树,并实例化所有需要响应的View。

ListView通过回收一些不可见的Views,通常在Android源码中称为“ScrapView(废弃的View)”来解决这个问题。这及意味着开发者只需要简单的更新每行的内容而不需要针对每个单独的行的布局来创建View。

为了实现第二点,在我们滑动屏幕时,ListView通过使用View回收器来增加低于或者高于当当前窗口的Views,并当前活动的Views移动到一个可回收池中。这样的话,ListView只需要在内存中保持足够多的Views去填充分配空间中的布局和一些额外的可回收Views,即使当你的Adapter有上百个items的适合。它会使用不同的方法去填充行之间的空间,从顶部或者底部等等,具体取决于窗口是如何变化的。

下面这个图很直观的展示了当你按下ListView的时候发生了什么:

ListView

通过上述介绍,相比我们已经熟悉了ListView的这种机制,让我们继续前往技巧部分。正如上述介绍的,在滑动时,ListView通过动态的创建和回收很多View,实现了尽可能地让Adapter的getView()轻量。所有的技巧都是通过多种方法让getView()更快。

View的回收

ListView每次需要在屏幕上显示新的一行的时候,会从其Adapter中调用getView()的方法。众所周知,getView()方法有3个参数:行的位置, convertView以及父ViewGroup。

参数convertView说穿来就是之前讲述的ScrapView。当ListView要求更新一行的布局时,convertView是一个非空值。因此,当convertView值非空时,你仅仅需要更新内容即可,而不需要重新一个新行的布局。getView()在Adapter中一般是如下的形式:

1
2
3
4
5
6
7
8
9
10
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.your_layout, null);
}

TextView text = (TextView) convertView.findViewById(R.id.text);
text.setText("Position " + position);

return convertView;
}

View Holder如何写的模板

Android很常见的一个操作就是在布局文件中找到一个内部的View。通常是使用一个findViewById()的View方法来实现的。这个findViewById()方法在View树中,根据一个View ID,会递归的被调用来找到其子树。虽然在静态UI布局中使用findViewById()是完全正常的。但是,在滑动时,ListView调用其Adapter中的getView()是非常频繁的。findViewById()可能会影响ListView滑动时的性能,尤其是你的行布局是很复杂的时候。

寻找一个充气布局内的内部观点是在Android上最常用的操作之一。这通常是通过一个名为findViewById(查看方法完成)。此方法将递归经过视图树寻找一个孩子用给定的ID码。静态的UI布局使用findViewById()是完全正常,但正如你所看到的,ListView中滚动时调用适配器的getView()非常频繁。 findViewById()可能perceivably击中ListViews,尤其是滚动的性能,如果你行的布局是不平凡的。

View Holder的模式就是减少在Adapter中getView()方法中调用findViewById()次数。实际上,View Holder是一个轻量级的内部类,用于直接引用到所有内部views。在创建View之后,你可以在每行的View存储为一个标签。通过这种方法,只需要在初次创建布局的时候调用findViewById()。下面是一个使用上述方法的View Holder模板的代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;

if (convertView == null) {
convertView = mInflater.inflate(R.layout.your_layout, null);

holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);

convertView.setTag(holder);
} else {
holder = convertView.getTag();
}

holder.text.setText("Position " + position);

return convertView;
}

private static class ViewHolder {
public TextView text;
}
阅读全文 »

By Long Luo

在一个Android应用中,Layout是开发中的一个很重要环节,Layout是组成UI不可缺少的一部分。

Android UI核心类

在Android应用构建UI的方法有以下几种:

  1. 单纯使用JAVA代码
  2. 使用XML完全定义界面
  3. 结合使用两者,在XML中定义,在JAVA中引用和修改

Android SDK中关于UI的核心类:

Android.view.View和android.view.ViewGroup

android中的常见UI控件均会扩展View和ViewGroup其中有一部分是专门用来控制其子View位置和大小,这些类我们称为布局管理器。

ViewGroup

  1. LayoutParams是ViewGroup内部类,包含了ViewGroup的布局参数,用来告诉它们的父类它们想怎么在父类中布局(大小和位置),所有在LayoutParams及其子类中定义的布局参数在xml中定义都是通过layout_***定义的。

LayoutParams只提供了两个参数设定:

layout_width  元素的高度(fill_parent | match_parent | wrap_content | *dip)
layout_height 元素的宽度(同上)                
  1. MarginLayoutParams也是ViewGroup一个内部类,它继承了LayoutParams类,用来扩展LayoutParams的属性,设置参数。

MarginLayoutParams添加了四个参数设定:

layout_marginLeft       相对于本元素左边界的偏移
layout_marginRight      相对于本元素右边界的偏移
layout_marginTop,       相对于本元素上边界的偏移
layout_marginBottom     相对于本元素下边界的偏移

以上的两种Layout参数,所有布局中的子ViewGroup和子View都可以使用

5种Layout

下面讲讲5种布局:

1. Linear Layout (线性布局)

线性布局是Android布局中最简单的布局,也是最常用,最实用的布局。 android:orientation线形布局的对齐方式 : vertical(垂直) 和 horizontal(水平) LayoutParams中的特殊参数:

layout_weight  权值
layout_gravity 相对于父元素的重力值(默认top|left):
(top|bottom|left|right|center_vertical|fill_vertical |center_ horizontal 
|fill_ horizontal | center| fill)

LinearLayout有两个非常相似的属性:

android:gravity
android:layout_gravity

他们的区别在于:

  • android:gravity属性是对该view中内容的限定.比如一个button 上面的text. 你可以设置该text相对于view的靠左,靠右等位置.
  • android:layout_gravity是用来设置该view相对与父view的位置.比如一个button在linearlayout里,你想把该button放在linearlayout里靠左、靠右等位置就可以通过该属性设置.

android:gravity用于设置View中内容相对于View组件的对齐方式,而android:layout_gravity用于设置View组件相对于Container的对齐方式。

原理跟android:paddingLeft、android:layout_marginLeft有点类似。如果在按钮上同时设置这两个属性。

android:paddingLeft="30px"  按钮上设置的内容离按钮左边边界30个像素
android:layout_marginLeft="30px"  整个按钮离左边设置的内容30个像素

下面回到正题, 我们可以通过设置android:gravity=“center”来让EditText中的文字在EditText组件中居中显示;

同时我们设置EditText的android:layout_gravity=“right”来让EditText组件在LinearLayout中居右显示。看下效果:

<LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    <EditText
        android:layout_width="wrap_content"
        android:gravity="center"
        android:layout_height="wrap_content"
        android:text="one"
        android:layout_gravity="right"/>
</LinearLayout>
阅读全文 »

By Long Luo

最近没怎么写东西的缘故是因为担心自己看的东西太少,读的东西太少,而想的太多。2014年的第一月也很快就要过去了,而我还没有对自己过去的一年里做出一点小结,就在这里随便扯几点吧!

比如我的大学好友雷大才子,精通几门外语,学富五车,不仅文章写得好,又懂音乐,还会写诗作画,更是一名勤劳的Blogger,每次看他的博文,总能学到很多东西。

一、Destiny

年轻的时候我看到网上一些晒东晒西的帖子,总想:“等我到了他那个年纪,应该比TA出色的多吧!”

但在工作了几年之后,我不得不认识到:和一些人相比,一方面由于家庭草根身份出身的巨大差距,另外一方面之前20多年的积累,导致除非出现巨大的机遇,否则人生绝无逆转的可能。关于这种巨大的差距,包括眼界、资源、机遇、圈子等,在第三节里面我会再认真的阐述。

被认为是20世纪最有影响力的经济学家之一的Frank H. Knight有个著名的观点:“决定一个人富有的三个条件,一是出身,二是机遇,三是努力,而这三者之中,努力是最微不足道的。

我更喜欢英语的Destiny,因为让我想起一个词:Destination,我想一个人的命运也就意味着这个人一生中最终能到达什么样的地方。一个人就像森林里的一棵树苗,最初你长在什么地方,加上你的天性,除非特别的机遇,你能够长到多高是可以预见的

我很羡慕凤姐,有其是我这种间歇性缺乏自信的人,更需要学习凤姐的自信和强大的内心,相比漂在大城市的广大千千万屌丝蚁族来说,凤姐完成了大改变,不仅不用再重复父辈的贫困,很大程度的改变了社会地位,也不需要像天朝这种Hard模式活动这么累了。

即使凤姐不去USA,比起绝大多数打工仔打工妹来说,凤姐上电视台,接受各种采访,人生经历也足够丰富。

2013的经历也许足够丰富,只是自己缺乏总结,导致又被同样的石头绊倒了2次。是时候好好回顾下了,做出改变。

除了老婆孩子不能变之后,其他的统统都要变。
                                    ---李健熙

二、这些年来的折腾

2013年自己折腾了不少,写了一些技术博客,也写了一些日志。

也许是小时候太没见过世面了,导致长大后努力想体验各种东西,到各种地方,了解各种知识,满足自己旺盛的好奇心和欲望。

建了个个人主页,折腾了html/css/php/js的知识,把网站搞的高大上点,虽然大部分是copy的。

建设个人主页初心就是宣传自己,树立我的个人品牌了,虽然目前人气不是很足,但是

  1. 个人主页

  2. Github Blog

引用雷才子的话来说,真正学到手的东西,只要没到你临死的那天,都会发挥它的作用。所以我要努力的锻炼身体,让自己活得很长很长。

我就像那棵树,现在起劲的折腾,是不是只是为了让自己那棵树的下限能够再高一点?

生命不息,折腾不止。

阅读全文 »

By Long Luo

又是一个周末,说明这一周又飞速的过去了,我的时间沙漏的沙子实在是过的太快了,尤其是在这个年龄,几乎是哭着送走每一天的

上午起床后想把WordPress Android客户端自己编译出来的,下载好了之后,可是编译遇到大问题,现在还没用解决,希望再花一个小时可以搞定。

最近想做一个项目:主页和博客应用。可以做到展示我写的博客,给自己2周的时间,我相信我可以完成的。

这一周发生了很多事,周五晚上的年会,啥大奖都没中。

我希望下周可以把《暗时间》这本书看完,这本书确实写的非常好,相见恨晚。

下午3点的时候去了世界之窗附近的一家音乐培训机构,体验了45分钟的吉他教程,收获相当大。吉他老师保养的非常好,33岁,但看起来也就20几岁的样子,香港出生,但现在已经移民到枫叶国去了。

谈谈收获:

  1. 高水平老师就是不一样,就像读过的好的技术书籍,让你如沐春风,不过$180一节课;
  2. 之前我认为手指短是学吉他钢琴的一个障碍,但事实证明,老师的手指还比我短;
  3. 自信心缺乏,是我做很多事情遇到的一个问题,我没那么差啊,为什么那么缺乏自信心呢?
  4. 我想学会吉他,学会一门才艺,但是价格感觉好贵的,自学吧。

一个人只有多思考,勤于思考,才能有所成就。

思考,见识更大的世界。

草草写完,其实这周的总结还不够。

Long Luo PM19:00 ~ PM19:30 @Jan. 19th, 2014 at Shenzhen, China.

By Long Luo

旅行,就是从自己活腻的地方跑到别人活腻的地方去。
                                 ---题记

来深已经4年多了,但是东部华侨城一直没去过,一方面是个人一直对一些人造的风景不是特别感冒,然后一方面就是远加门票价格高。部门组织了今天去东部华侨城一日游的活动,于是就顺便游玩了下OCT,在此记录下感想。

早上6:30爬起来,洗漱完毕,看了下天气,7°~15°,温度不高也不低,但是自己也没有比平常多穿衣服,也确实也没啥衣服,一直都是那几件衣服,再冷的天气都那样。最后证明今天不是游华侨城的好日子。

好大的风,一天的时间就把我的手吹裂了,护手霜需要get。

一、人造的风景

一直以来,喜欢的风景,要么是各大城市的中心区,不管是繁华的商业区,还是车水马龙的主干道,抑或是鳞次栉比的商店,当然少不了美味小吃;要么就是没有人工雕琢痕迹的景区公园,比如九寨沟、雪山、森林公园、海滩等。国内很多景点都把原有的文物古迹给拆了,然后复刻一个,简直是令人发指啊,完全是一堆不懂艺术的公园在胡搞啊!

对于OCT这种定义在休闲娱乐的主题公园来说,恰恰需要在宣传时宣传其人造风景,比如大峡谷什么亚洲第一大、第一长、第一快等等。没去过茶溪谷,但是对于大部分没去过欧洲旅游的普通大众来说,也是一种廉价体验欧洲小镇的好途径。

反正对于我来说,惊险刺激性的体验一次就够了,除非特殊原因,不会想参加第二次。

二、攻略 & 良心推荐

对于看到了这篇小文,希望下次去OCT的同学来说,在此给点攻略建议: 进去之后,直接前行至缆车处,上山,云霄轮盘活动,这个建在山顶上,不过不推荐冬天参加,道理你懂得,高处不胜寒。

云霄轮盘可以参加360°观光塔,晚了的话,排队比较长,不过也挺快。

玩完这2个项目,下山玩剩下的项目:

必玩项目推荐:木质过山车,给4星半。惊险刺激,体验那种失速失重的感觉,最好不过了,前提是你血压心脏均正常,同时这个项目提供买一附送一大波尖叫声。

不过不知道是OCT故意省钱还是真的在维修,上午没有开通过山车,导致下午排了很长很长的队。

地心4KM坑爹啊,4D影院 & 真人CS吐血阻止你去!

阅读全文 »
0%