Android 代码优化小提示
代码逻辑相关
遍历一个List集合
bad:
1 | List<User> userList = new ArrayList<>(); |
better:
1 | List<User> userList = new ArrayList<>(); |
①、第二种方式把 userList.size() 用变量 size 存值避免了每次迭代都去调用该方法(不要在 for 循环的第二个表达式的判 断调用对象的方法或字段);②、把 user 变量的声明放到循环外边,避免每次使用都去声明一下 User 对象。 ③、getCount() 方法的处理也类似,如用 int count = xxx.getCount() 缓存起来。
遍历HashMap的最佳方法
1 | Map<String, User> userMap = new HashMap<>(); |
字符串
判断字符串str是否为null或空串
bad:
1 | if (null == str || "".equals(str)) { |
better:
1 | if (TextUtils.isEmpty(str)) { |
TextUtils 是一个非常好用的工具类,把 List 转成字符串,逗号分隔;逗号分隔的 String 字符串,切割成 List ,分别可以 用 TextUtils 的 join 和 split 方法。
容易报空指针的情况
判断一个字符串的内容是否为某值
bad:
1 | if (str.equals("hello")) { |
better:
1 | // 避免空指针异常,应该把常量写在前面 |
判断集合某个元素对象的某个字段是否为空
bad:
1 | // 如果元素对象为 null 这里就挂了吧 |
better:
1 | // 使用对象的方法或字段时,考虑下对象本身是否可能为 null |
常用资源释放
Cursor
1 | try { |
流文件
1 | public class Test { |
WebView
- 首先就是使用自己封装的 WebView , 不在 xml 里面声明,而是直接代码 new 个对象,传入 application context 防止 activity 引用滥用。
1 | webView = new BridgeWebView(getContext().getApplicationContext()); |
在使用了这个方式后,基本上 90% 的 webview 内存泄漏的问题便得以解决。
- 而在 Android 4.4 版本以下,会出现 Android Webview 无法自动释放,如在 Fragment 中,使用 onDetach 来释放 Webview 是比较好的时机。
1 | public void onDetach() { |
参考文章:
Android WebView: 性能优化不得不说的事
android内存优化之webview
Handler
- 使用弱引用
1 | public class NoLeakActivity extends Activity { |
- 及时清除消息
1 | public class NoLeakActivity extends Activity { |
其它
反面判断条件
bad:
1 | public void testMethod(ArrayList<User> userList) { |
better:
1 | public void testMethod(ArrayList<User> userList) { |
很多比较复杂的层级判断都可以从这些判断的反面出发,来降低程序的复杂性,从而提高可读性。
if与return搭配
bad:
1 | public int testIfElse(String cmd) { |
better:
1 | public int testIfElse(String cmd) { |
对象序列化
Android 中的序列化官方推荐 Parceble , 其实 Parceble 最好用于内存之间数据的交换,如果要把数据写入硬盘的话,推荐实现 Serializable .
SharedPreferences
SharedPreferences.Editor.commit
这个方法是同步的,一直到把数据同步到 Flash 上面之后才会返回,由于 IO 操作的不可控,尽量使用 apply 方法代替。apply 只在 API Level >= 9 才会支持,需要做兼容。不过,最新的 support v4 包已经为我们做好了处理,使用 SharedPreferencesCompat.EditorCompat.getInstance().apply(editor)
即可。
其它优化
静态变量不要直接或者间接引用 Activity、Service 等。这会使 Activity 以及它所引用的所有对象无法释放,然后,用户操作时间一长,内存就会狂升。
Handler 机制有一个特点是不会随着 Activity、Service 的生命周期结束而结束。也就是说,如果你 Post 了一个 Delay 的 Runnable , 然后在 Runnable 执行之前退出了 Activity , Runnable 到时间之后还是要执行的。如果 Runnable 里面包含更新 View 的操作,程序崩溃了。
不少人在子线程中更新 View 时喜欢使用
Context.runOnUiThread
, 这个方法有个缺点,就是一但 Context 生命周期结束,比如 Activity 已经销毁时,一调用就会崩溃。Application 的生命周期就是进程的生命周期。只有进程被干掉时,Application 才会销毁。哪怕是没有 Activity、Service 在运行,Application 也会存在。所以,为了减少内存压力,尽量不要在 Application 里面引用大对象、Context 等。
Activity 的 onDestroy 方法调用时机是不确定的(有时候离开界面很久之后才会调用 onDestroy 方法),应该避免指望通过 onDestroy 方法去释放与 Activity 相关的资源,否则会导致一些随机 bug .
如果使用
Context.startActivity
启动外部应用,最好做一下异常预防,因为寻找不到对应的应用时,会抛出异常。如果你要打开的是应用内的 Activity , 不防使用显式 Intent , 这样能提高系统搜索目标 Activity 的效率。如果子类实现 Serializable 接口而父类未实现时,父类不会被序列化,但此时父类必须有个无参构造方法,否则会抛 InvalidClassException 异常。
transient
关键字修饰变量可以限制序列化。View.getContext
获取控件上下文,写 RecyclerView 的 Adapter 的时候,为了使用 LayoutInflater , 不用在构造函数中传入一个外部的 context .
UI相关
Space
Space 经常用于组件之间的缝隙,其 draw()
为空,减少了绘制渲染的过程。组件之间的距离使用 Space 会提高了绘制效率,特别是对于动态设置间距会很方便高效。正是因为 draw()为空,对该 view 没有做任务绘制渲染,所以不能对 Space 设置背景色。
tools标签
tools 标签可以很好的帮助开发者实时预览 xml 的效果,并且运行以后 tools 标签的内容不会展示出来。例如:
1 | <TextView |
ContextCompat
Android 6.0 之后 getResources().getColor()
被废弃了,可用 ContextCompat.getColor(context, R.color.color_name)
替换,ContextCompat 是 v4 包里的,请放心使用,另外还有 getDrawable()
等方法。