android 客户端开发中,很多ui细节要处理,这里就总结下工作中用到的和会用到的ui 方法的优化知识:
一,布局优化:
public_layout.xml
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:orientation="vertical"
4 android:layout_width="fill_parent"
5 android:layout_height="fill_parent"
6 >
7 <TextView
8 android:layout_width="fill_parent"
9 android:layout_height="wrap_content"
10 android:text="public_view"
11 />
12 </LinearLayout>
- <include/> 标签的使用:很容易就能做到共享和重用布局,方便管理页面公用的布局,类似topBar,bottomBar
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:orientation="vertical"
4 android:layout_width="fill_parent"
5 android:layout_height="fill_parent">
6 <include android:id="@+id/new" layout="@layout/public_layout"></include>
7 </LinearLayout>
- <merge/>标签的使用:一般情况下能够帮我们减少一个布局层次,用法有点复杂,提升不大,不建议使用~;
1 <?xml version="1.0" encoding="utf-8"?>
2 <merge xmlns:android="http://schemas.android.com/apk/res/android"
3 <include android:id="@+id/newone" layout="@layout/public_layout"></include>
4 <include android:id="@+id/newtwo" layout="@layout/public_layout"></include>
5 </merge>
- <Viewstub/>标签的使用:很多情况下,一个布局中有很多View并不常用,这就造成了资源的浪费,android为此提供了ViewStub标签来解决这个问题。在默认情况下ViewStub下的标签都有visibility=GONE属性(不可见),更重要的是在这个标签下的内容不会占用任何的空间。其实ViewStub和include类似,不过区别就在于ViewStub只会在你需要的时候进入你的界面,viewStub通过inflate()方法来通知系统加载其内部的View。这样就可以让我们既享受到<include/>的便利,又不会产生过多没用的View。main.xml:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:orientation="vertical"
4 android:layout_width="fill_parent"
5 android:layout_height="fill_parent"
6 >
7 <Button
8 android:id="@+id/show"
9 android:layout_width="wrap_content"
10 android:layout_height="wrap_content"
11 android:text="点击导入"
12 />
13 <ViewStub
14 android:id="@+id/viewStub"
15 android:layout="@layout/public_layout"
16 android:layout_width="wrap_content"
17 android:layout_height="wrap_content"
18 />
19 </LinearLayout>
在代码中应用:
ViewStub stub = (ViewStub) findViewById(R.id.stub);
View inflated = stub.inflate();
ViewStub的一些特点:
1. ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了。
2. ViewStub只能用来Inflate一个布局文件,而不是某个具体的View,当然也可以把View写在某个布局文件中。
基于以上的特点,那么可以考虑使用ViewStub的情况有:
1. 在程序的运行期间,某个布局在Inflate后,就不会有变化,除非重新启动。
因为ViewStub只能Inflate一次,之后会被置空,所以无法指望后面接着使用ViewStub来控制布局。所以当需要在运行时不止一次的显示和隐藏某个布局,那么ViewStub是做不到的。这时就只能使用View的可见性来控制了。
2. 想要控制显示与隐藏的是一个布局文件,而非某个View。
因为设置给ViewStub的只能是某个布局文件的Id,所以无法让它来控制某个View。
所以,如果想要控制某个View(如Button或TextView)的显示与隐藏,或者想要在运行时不断的显示与隐藏某个布局或View,只能使用View的可见性来控制。
- 使用sdk自带的 Hierarchy Viewer工具,这是一个非常好的布局优化工具,同时,你也可以通过它学习他人的布局。详细方法可以参考:
- layoutopt 工具,也不错 ,只是ADT 16之前的sdk 才能使用,后被google放弃了;
- Lint的使用,这是一个很不错的,很强大的UI帮助工具;每个错误都有详细的解释,可以直接定位到源码链接,错误行,直接提供修改的意见,可以生成html 文档
- 减少不必要的View以及View的嵌套层次。比如实现一个listview中常用的layout,可以使用RelativeLayout减少嵌套,要知道每个View的对象会耗费1~2k内 存,嵌套层次过多会引起频繁的gc,造成ANR。
- Drawing and Invalidating : 在Android开发过程中,每个View的内容并非都是一成不变的。在变更View的内容后,我们需要进行刷新使得屏幕上的内容与之一致。
一般来说这个操作直接调用View.invalidate()刷新整个View即可。然而很多情况下,内容变更的区域并不是整个View,而只是其中的一部分。这时如果仍然直接调用View.invalidate()的话代价就显得有些高昂,一种推荐的方法是改为调用View.invalidate(Rect)或者View.invalidate(left, top, right, bottom)刷新View的指定区域。
10,Background and Images :我们可以对任何View设置背景图像Background drawable,应用程序在显示View时会自动进行拉伸、缩放(Auto-scale)使图像能够完全填充View的显示区域,而在运行时拉伸/缩放图像显然会降低程序运行效率(计算成本高,容易引发Out of Memory)。
// Rescales originalImage to the size of view using
// bitmap filtering for better results
originalImage =Bitmap.createScaledBitmap( originalImage,// bitmap to resize
view.getWidth(),// new width
view.getHeight(),// new height
true);// bilinear filtering
11,通过theme 预加载背景 或者窗口不需要背景的时候设置@null
1 <!-- res/values/styles.xml -->
2 <resources>
3 <style name="Theme.NoBackground" parent="android:Theme">
4 <item name="android:windowBackground">@null</item>
5 </style>
6 </resources>
在activity中设置
1 <activity
2 android:name="MyApplication"
3 android:theme="@style/NoBackgroundTheme">
4 <!-- intent filters and stuff -->
5 </activity>
二,adapter优化:
adapter 是数据与view之间的桥梁,类似listview 中使用baseAdapter ,getView()方法的优化是关键
比较成熟的优化方案:
1 static class ViewHolder
2 {
3 TextView text;
4 ImageView icon;
5 }
6
7 public View getView( int position, View convertView, ViewGroup parent )
8 {
9 ViewHolder holder;
10
11 if ( convertView == null )
12 {
13 convertView = mInflater
14 .inflate( R.layout.list_item_icon_text, null );
15
16 holder = new ViewHolder( );
17 holder.text = ( TextView ) convertView.findViewById( R.id.text );
18 holder.icon = ( ImageView ) convertView.findViewById( R.id.icon );
19
20 convertView.setTag( holder );
21 }
22 else
23 {
24 holder = ( ViewHolder ) convertView.getTag( );
25 }
26
27 holder.text.setText( DATA[ position ] );
28 holder.icon.setImageBitmap( ( position & 1 ) == 1 ? mIcon1 : mIcon2 );
29
30 return convertView;
31 }
如果对性能要求比较高可以 硬编码 布局,不使用耗时的xml,xml加载解析为java代码是耗时的,findviewByid 也是耗时的;
总结:1,重用convertView;2,较少查询次数 findviewbyid;3,分段加载listview (分页);4,布局硬编码