本文的内容均来自Android SDK文档Resources下的Articles,本文对一些比较有用、常用的知识做一个简要的总结。
1、避免内存泄露
Context经常用来加载访问各种Resources,这就是为什么很多控件在创建的时候都要传入一个Context的原因。我们的程序大多数会使用到两种Context:Activity和Application,而且我们大多数使用前一个。
在一个Context-Activity的全局变量中不要保存Drawable、View、Context-Activity的引用,因为Drawable和View各自保存Context的引用,如果在全局变量中保存,那么当Activity销毁重新创建后会造成内存泄露。如果要在上下文中保存全局变量,请用Context-Application。
中文参考:http://www.cnblogs.com/xirihanlin/archive/2010/04/09/1707986.html
2、向后兼容性
Android各个版本存在着差异,为了编写出兼容性比较强的程序,除了设置<uses-sdk android:minSdkVersion="3" />之外, 我们可以通过反射机制去实现这种兼容性,如,使用 android.os.Debug.dumpHprofData(String filename),该方法只在Android1.0中去实现,但在Android1.5中并不支持,我们可以通过反射机制实现:
private static void initCompatibility() { try { mDebug_dumpHprofData = Debug.class.getMethod( "dumpHprofData", new Class[] { String.class } ); /* success, this is a newer device */ } catch (NoSuchMethodException nsme) { /* failure, must be older device */ } } private static void dumpHprofData(String fileName) throws IOException { try { mDebug_dumpHprofData.invoke(null, fileName); } catch (InvocationTargetException ite) { /* unpack original exception when possible */ Throwable cause = ite.getCause(); if (cause instanceof IOException) { throw (IOException) cause; } else if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } else { /* unexpected checked exception; wrap and re-throw */ throw new RuntimeException(ite); } } catch (IllegalAccessException ie) { System.err.println("unexpected " + ie); } }
3、判断Intent服务是否存在
Android为我们提供了非常多的Intent,也有第三方提供了很多Intent供我们使用,但由于版本、用户是否安装等原因,我们不清楚该Intent是否在本机上能否使用,为此,就要进行判断。代码如下:
public static boolean isIntentAvailable(Context context, String action) { final PackageManager packageManager = context.getPackageManager(); final Intent intent = new Intent(action); List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); return list.size() > 0; }
4、Drawable Mutations
Drawable允许我们在不同的View之间共享资源,具体共享的实现机制是通过一个叫作"constant state"的方式去实现的,它保存了一个资源的所有的属性,比如,在一个Button中,constant state保存了Button的bitmap,整个程序默认的Button都是共享使用这个bitmap,从而节省了内存空间。constant state简单的理解如下图:
constant state的方式避免了很多内存的浪费,但是在实际的应用过程中如:试图修改Drawable的constate state,也遇到一些问题,比如,我们用一个ListView显示书籍列表,每个Book Item由一个星形的Drawable和Text构成,当该书是我们喜欢的书籍时,就显示该星形,反之,就使这个星形半透明。这个实现的大致代码如下:
Book book = ...; TextView listItem = ...; listItem.setText(book.getTitle()); Drawable star = context.getResources().getDrawable(R.drawable.star); if (book.isFavorite()) { star.setAlpha(255); // opaque } else { star.setAlpha(70); // translucent }
不幸的是,我们发现这个代码无效,所有的星形Drawable都是一样的。如下面左图:
如果我们使用了一个新的Drawable,但是因为BookItem的Drawable都引用到了同一个Constant state,因此我们尝试对Constatn state进行修改的时候,引用该Constant state的Drawable也会相应的改变。
Android 1.5以上版本提供了解决的办法:使用mutate()方法,使用该方法时,Drawable的Constant state会被复制,从而不会影响其他的Drawable,使用方式如下:
Drawable star = context.getResources().getDrawable(R.drawable.star); if (book.isFavorite()) { star.mutate().setAlpha(255); // opaque } else { star. mutate().setAlpha(70); // translucent }
调用后效果如下图: