分类: Java
2011-11-10 10:56:28
32. Android程序内存管理必读
很多开发者都是从J2ME或J2EE上过来的,对于内存的使用 和理解并不是很到位,Android开发网本次给大家一些架构上的指导,防止出现豆腐渣工程的出现。Android作为以Java语言为主的智能平台对于 我们开发一些高性能和质量的软件来说了解Android程序内存管理机制是必须的。 Android的Dalvik VM在基础方面和Sun JVM没有什么大的区别仅仅是字节码的优化,我们要知道什么时候用gc什么时候用recycle以及到底用不用finalization,因为Java对 内存的分配只需要new开发者不需要显示的释放内存,但是这样造成的内存泄露问题的几率反而更高。
1.对于常规开发者而言需要了解 Java的四种引用方式,比如强引用,软引用,弱引用以及虚引用。一些复杂些的程序在长期运行很可能出现类似OutOfMemoryError的异常。
2.并不要过多的指望gc,不用的对象可以显示的设置为空,比如obj=null,这里Android123提示大家,java的gc使用的是一个有向图,判断一个对象是否有效看的是其他的对象能到达这个对象的顶点,有向图的相对于链表、二叉树来说开销是可想而知。
3.Android为每个程序分配的对内存可以通过Runtime类的totalMemory() freeMemory() 两个方法获取VM的一些内存信息,对于系统heap内存获取,可以通过Dalvik.VMRuntime类的getMinimumHeapSize() 方法获取最小可用堆内存,同时显示释放软引用可以调用该类的gcSoftReferences() 方法,获取更多的运行内存。
4.对于多线程的处理,如果并发的线程很多,同时有频繁的创建和释放,可以通过concurrent类的线程池解决线程创建的效率瓶颈。
5. 不要在循环中创建过多的本地变量。
有关Android和Java的系统性能分析,Android123将在以后的文章中详细讲述如何调试Java分析内存泄露以及Android上的gdb调试器分析得出内存性能改进。
33. Android中内嵌字体实现个性化
在 Android中我们的应用可以灵活的内嵌自己的字体文件,实现各个手机上可以正常的显示个性化文字,我们都知道TextView的 setTypeface方法可以设置目标文字的显示特性,比如字体、颜色、粗体、斜体等。我们直接找一个TrueTypeFont的字体文件即.ttf, 对于Win32系统的用户可以直接在Windows/fonts文件夹中能找到很多。比如微软雅黑就不错,可是体积太大,由于Android的 Assets类有单个文件1MB体积的限制,我们先找个英文字体做测试。这里我们将字体文件android123.ttf放到工程的assets文件夹的 fonts目录中。
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/android123.ttf");
TextView tv = (TextView)findViewById(R.id.text);
tv.setTypeface(tf); //设置TextView的风格
tv.setText("CWJ Test");
tv.setTextSize(12);
tv.setTextColor(Color.RED);
34. 获取和设置ListView的选择项
获 取当前选中项 int curPos = listView.getFirstVisiblePosition(); 当然是用getItemAtPosition(int nPos)方法也可以 ,设置当前选择位置 listView.setSelectedPosition(lastPos); 对于基于AbsListView为基类的ListView等控件均可以使用这种方法。
35. android.text.format文件大小和日期解析类
很多网友可能直接将自己的J2ME项目生硬的移植到Android平台,其实Google为我们提供好了文件大小和时间日期解析类,它位于android.text.format这个包中,它提供了强大的标准化解析方法:
1. IP地址解析类 在android.text.format.Formatter中提供了String formatIpAddress(int addr) 这个方法可以轻松方便的将socket中的int型转成类似127.0.0.1的IP格式,需要注意的是Linux平台的字节顺序,即小字节序、低字节序 little-endian。
2. 文件大小解析类 细心的网友可能还看到了android.text.format.Formatter中的formatFileSize方法,该方法String formatFileSize (Context context, long number) ,第二个参数是long型,一般为File对象的最后修改时间或创建时间的方法,最终返回类似 12KB、5Bytes的值,20MB的字符串。
3. 日期时间解析类 ,该类位于android.text.format.DateFormat这个package中,该类提供了Java中的三种时间对象,Android123提示大家下面三种方法为静态可以直接调用,如下:
final static CharSequence format(CharSequence inFormat, Date inDate) //传入Date对象
Given a format string and a Date object, returns a CharSequence containing the requested date.
final static CharSequence format(CharSequence inFormat, Calendar inDate) //Calendar对象
Given a format string and a Calendar object, returns a CharSequence containing the requested date.
final static CharSequence format(CharSequence inFormat, long inTimeInMillis) //long对象
Given a format string and a time in milliseconds since Jan 1, 1970 GMT, returns a CharSequence containing the requested date.
我们可能看到了第一个参数均为inFormat这是一个CharSequence接口的String类型,它提供了灵活的时间格式解析字符串描述,Android开发网提示大家注意大小写要区分,如
April 6, 1970 at 3:23am 例子,那么inFormat参数的写法和最终执行的结果如下对照,下面就以Android123的CWJ生日为例子如下
"MM/dd/yy h:mmaa" -> "11/03/87 11:23am"
"MMM dd, yyyy h:mmaa" -> "Nov 3, 1987 11:23am"
"MMMM dd, yyyy h:mmaa" -> "November 3, 1987 11:23am"
"E, MMMM dd, yyyy h:mmaa" -> "Tues, November 3, 1987 11:23am"
"EEEE, MMMM dd, yyyy h:mmaa" -> "Tuesday, Nov 3, 1987 11:23am"
对于判断一个时间是否为24小时制式可以通过android.text.format.DateFormat类的static boolean is24HourFormat(Context context)方法来判断。
36. Android代码性能优化技巧
目前来说Android 2.2的JIT性能有了本质的提高,不过对于老版本的程序提高Java执行效率还有很多语言特点来说,今天Android123提到的不是语法糖,而是基础的问题,对于Java 1.5之后将会有明显的改进。下面的例子来自SDK:
static class Foo {
int mSplat;
}
Foo[] mArray = ...
上面的静态类Foo的执行效果和性能,我们分三个方法zero、one和two来做对比。
public void zero() { //大多数人可能简单直接这样写
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
public void one() { //通过本地对象改进性能
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
public void two() { //推荐的方法,通过Java 1.5的新语法特性可以大幅改进性能
int sum = 0;
for (Foo a : mArray) {
sum += a.mSplat;
}
}
zero() is slowest, because the JIT can't yet optimize away the cost of getting the array length once for every iteration through the loop.
one() is faster. It pulls everything out into local variables, avoiding the lookups. Only the array length offers a performance benefit.
two() is fastest for devices without a JIT, and indistinguishable from one() for devices with a JIT. It uses the enhanced for loop syntax introduced in version 1.5 of the Java programming language.
37. Android开发注意点 Part One
Android已经的很多细节问题我们通过平台开发总结不断完善这个列表,如果你有相关的内容可以联系 .
一、AssetManager - 已知单个文件处理不能大于1MB,所以如果资源很大,建议使用Zip格式压缩存放。
二、ScrollView中嵌入ListView - 这个作法可能会出现你的ListView仅仅显示1行半。
三、Android自带的Zip处理类对文件名编码无法识别,也没有提供显示的设置方法,在zlib中写死了。
四、使用一些资源对象记住关闭,比如对于文件流对象最后
FileOutputStream os = xxx;
try {
//dosomething
} finally {
os.close(); //显示的使用finally关闭文件对象。
}
对于Cursor而言,在移动位置时首先判断Cursor是否为空,最终使用完仍然需要 close方法,如果重用,可以使用deactivate方法释放当前资源,通过requery方法再次查询。
五、SDK中标记为 deprecated 字样的,常规情况下是有更好的方法可以替代,短期内可以放心使用。这些方法一般高版本的SDK都可以向上兼容,目前尚未发现Android放弃某些API的支持。
六、Notification的Intent无法传递到目标的Activity,Service和Broardcast没有测试过,中途需要通过PendingIntent,可能这里出现了问题。
38. Android上HTTP协议通讯状态获取
通 常情况下轻量级的Http传输Android平台可以直接使用Sun Java的HttpURLConnection类方法处理,比如果自己定义一次请求header可以通过setRequestProperty设置,而我 们需要获取的Http Web Server状态可以通过HttpURLConnection.getResponseCode() 的方法获取。
当然Http协议返回值常见的有 200 为成功,400为请求错误,404为未找到,500为服务器内部错误,403无权查看,302为重定向等等。
对于Android平台提供更完善的Apache类有HttpClient 、HttpPost、HttpResponse、HttpGet和HttpEntity,其中对于数据报头header构造通过HttpEntity,而 返回状态值可以通过HttpResponse获取。
有关Android客户端和Server通讯类相关的开发我们将会在以后文章中做大量实例介绍。
39. Android布局Java代码构造法
一 般情况下对于Android程序布局我们往往使用XML文件来编写,这样可以提高开发效率,但是考虑到代码的安全性以及执行效率,可以通过Java代码执 行创建,虽然Android编译过的xml是二进制的,但是加载xml解析器的效率对于资源占用还是比较大的,一般一个简单的TextView,比如
android:layout_width="100px"
android:layout_height="wrap_content" />
可以等价于下面的Java代码:
LinearLayout.LayoutParams textParams = new LinearLayout.LayoutParams(100, LayoutParams.WRAP_CONTENT); //宽度为100px,高为自适应最小的高度
// setOrientation(VERTICAL); 设置布局为垂直
TextView textControl = new TextView(this);//如果从一个XXXLayout.,比如LinearLayout为View的基类时这里this应该换成为创建改类的Context
textControl.setText("Android开发网欢迎您");
addView( textControl, textParams );
当然Java处理效率比XML快得多,但是对于一个复杂界面的编写,可能需要一些套嵌考虑,如果你思维灵活的话,使用Java代码来布局你的Android应用程序是一个更好的方法。
40. 测试Android软件性能主要方法
对于Android平台上软件的性能测试可以通过以下几种方法来分析效率瓶颈,目前Google在Android软件开发过程中已经引入了多种测试工具包,比如Unit测试工程,调试类,还有模拟器的Dev Tools都可以直接反应执行性能。
1. 在模拟器上的Dev Tools可以激活屏幕显示当前的FPS,CPU使用率,可以帮助我们测试一些3D图形界面的性能。
2. 一般涉及到网络应用的程序,在效率上和网速有很多关系,这里需要多次的调试才能实际了解。
3. 对于逻辑算法的效率执行,我们使用Android上最普遍的,计算执行时间来查看:
long start = System.currentTimeMillis();
//android开发网提示这里做实际的处理do something
long duration = System.currentTimeMillis() - start;
最终duration保存着实际处理该方法需要的毫秒数。这里类似Win32上的GetTickCount,在Win 32和Symbian上都提供了高精度的性能计数器和低阶计时器,这里在Dalvik VM上的Java层这种方法对于一般的应用足以。
4. GC效率跟踪,如果你执行的应用比较简单,可以在DDMS中查看下Logcat的VM释放内存情况,大概模拟下那些地方可以缓存数据或改进算法的。
5. 线程的使用和同步,Android平台上给我们提供了丰富的多任务同步方法,但在深层上并没有过多的比如自旋锁等高级应用,不过对于Service和 appWidget而言,他们实际的产品中都应该以多线程的方式处理,以释放CPU时间,对于线程和堆内存的查看这些都可以在DDMS中看到。
更多的调试和性能测试方法Android123将在以后的内容中出现。
41. Splash Screen开场屏在Android中的实现
很 多网友可能发现近期Tencent推出的手机QQ Android版包含了一个开场屏Splash Screen载入效果,通常游戏或大型软件打开时可能需要一个释放解析资源的过程,需要一个前台的动画播放和后台的逻辑处理线程配合,当然对于简单的软件 也可以加一个Splash Screen作为美化。在Android平台上如何实现呢?
首先创建一个Activirty,在SetContentView时直接通过ImageView创建一个全屏的图片,Android123提示大家还要考虑好分辨率和当前设备一致,onCreate添加代码如下:
new Handler().postDelayed(new Runnable(){ // 为了减少代码使用匿名Handler创建一个延时的调用
public void run() {
Intent i = new Intent(SplashScreen.this, Main.class); //通过Intent打开最终真正的主界面Main这个Activity
SplashScreen.this.startActivity(i); //启动Main界面
SplashScreen.this.finish(); //关闭自己这个开场屏
}
}, 5000); //5秒,够用了吧
42. Android的Activity你知多少呢?
看 到这个标题很多网友肯定回答,我知道Activity是Android上的窗口基类,了解Activity的生命周期比如onCreate onStop等,呵呵,按照这样说Android123还知道Activity的实现其实是从ApplicationContext,而 ApplicationContext是从Context这个抽象类派生而来的,当然我们看到显示的是View或者ViewGroup,当然今天说的不是 这些东西,而是很多网友来问的Android为什么不设计一个任务管理器,当然从Android 1.5开始ActivityManager类提供了restartPackage可以关闭一个程序,需要加上
我们在一个普通的程序主窗口A中打开了一个窗口B,而窗口B打开了窗口C,但是按下Back键后结果出乎了预期,是的这就是Activity的 history stack的原因,在数据结构中栈是FIFO的,阻止我们不愿意看的情况的发生则可以在打开新Activity时加上标记 FLAG_ACTIVITY_NO_HISTORY,代码如下:
Intent i= new Intent(this, cwj.class);
i.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); //Android开发网提示大家相关的还有Intent.FLAG_ACTIVITY_CLEAR_TOP,都试试
startActivity(i);
当然更多的程序Activity控制可以再androidmanifest.xml中定义。
43. JSONObject在Android上的应用
如 果你过去开发过AJAX应用,相信对JSONObject不会陌生吧,作为基于JavaScript的数据交换格式,可以直接代替Xml,这里 Android从1.0开始就完全支持JSONObject。在平时应用中直接引入import org.json.JSONObject;即可方便使用。当然同类的还有SOAP。
在常规使用方便JSONObject对象可以实现类似Bundle或Parcel可以封装数据,代替一个XML的ITEM,但最大的优势是可以执行一些简 单的方法,比如说getString、has、put、getBoolean、getInt等数据类型的存取操作。Android123提示大家对于常规 的项目开发,今天本文不考虑Server端的布局,在Android平台上处理这些比较简单,主要是一些http的请求处理。可以直接引入import org.apache.http.xxx来实现web server层的数据交换,如果你没有专业的Server开发技术,可以通过简单的Web配合JSON方式快速实现自己的交互式应用。
44. Android高性能文件类MemoryFile
很 多网友抱怨Android处理底层I/O性能不是很理想,如果不想使用NDK则可以通过MemoryFile类实现高性能的文件读写操作。 MemoryFile顾名思义就是内存文件的意思,如果你过去从事过Win32开发,那么它的原理就是MapViewOfFile(),当然开发过 Linux的网友可能很快就联想到了mmap(),是的该类就是他们的托管代码层封装,位于android.os.MemoryFile这个位置,从 Android 1.0开始就被支持。
MemoryFile适用于哪些地方呢?
对于I/O需要频繁操作的,主要是和外部存储相关的I/O操作,MemoryFile通过将 NAND或SD卡上的文件,分段映射到内存中进行修改处理,这样就用高速的RAM代替了ROM或SD卡,性能自然提高不少,对于Android手机而言同 时还减少了电量消耗。Android123提示网友该类实现的功能不是很多,直接从Object上继承,通过JNI的方式直接在C底层执行。
主要的构造方法 MemoryFile(String name, int length) ,这里第二个参数为文件大小,需要说明的是Android的MemoryFile和传统的mmap还有一点点区别,毕竟是手机,它内部的内存管理方式 ashmem会从内核中回收资源。毕竟目前部分低端机型的RAM也比较吃紧。
synchronized boolean allowPurging(boolean allowPurging) //允许ashmem清理内存,线程安全同步的方式。
void close() //关闭,因为在Linux内部mmap占用一个句柄,不用时一定要释放了
InputStream getInputStream() 返回读取的内容用Java层的InputStream保存
OutputStream getOutputStream() 把一个OutputSream写入到MemoryFile中
boolean isPurgingAllowed() //判断是否允许清理
int length() //返回内存映射文件大小
下面就是我们熟悉的,读写细节,主要是对字符数组的操作,这里大家要计算好每个文件类型的占用,同时考虑到效率对于自己分配的大小考虑粒度对齐。
int readBytes(byte[] buffer, int srcOffset, int destOffset, int count)
void writeBytes(byte[] buffer, int srcOffset, int destOffset, int count)
具体的实际应用,Android开发网将在下次和大家讲到。
45. TextUtils类-Android字符串处理类
对于字符串处理Android为我们提供了一个简单实用的TextUtils类,如果处理比较简单的内容不用去思考正则表达式不妨试试这个在android.text.TextUtils的类,主要的功能如下:
是否为空字符 static boolean isEmpty(CharSequence str)
拆分字符串 public static String[] split (String text, String expression) ,Android开发网提示大家仔细看例子如下 String.split() returns [''] when the string to be split is empty. This returns []. This does not remove any empty strings from the result. For example split("a,", "," ) returns {"a", ""}.
拆分字符串使用正则 public static String[] split (String text, Pattern pattern)
确定大小写是否有效在当前位置的文本TextUtils.getCapsMode(CharSequence cs, int off, int reqModes)
使用HTML编码这个字符串 static String TextUtils.htmlEncode(String s)
46. InputSream输入流转String字符串,Android开发工具类
在 Android平台上使用Java层处理I/O时主要使用流,这里Android开发网给大家一个方便的类,可以处理InputStream输入流转为 String字符串,在效率上,我们使用了字符串拼接StringBuilder类减少内存碎片以及BefferedReader类实现一个缓存。
private String Stream2String(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is), 16*1024); //强制缓存大小为16KB,一般Java类默认为8KB
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) { //处理换行符
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
}
47. layout资源包含,android开发必读
有 时候我们在一个Android程序中可能会复用布局文件,这时可以在一个xml文件中复用过去的布局文件,但是和常规的使用不同的是,需要加上类似包含头 文件一样的include关键字,比如下面我们需要包含layout文件夹下的view.xml布局文件,需要
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
android:layout_height="wrap_content"
android:text="@string/cwj"
/>
android:layout_height="wrap_content"
android:text="@string/android123"
/>
http://hi.baidu.com/286177943/blog/item/74394125632f911b4c088db8.html