在android中经常会有一些多线程操作同一对象的问题,经常会发生空指针的情况,尤其是跑monkey测试时。
下面写点伪代码举例说明一下:
//已知mHandler为成员变量;
if (mHandler != null) {
mHandler.xxx();
mHandler.yyy();
}
上面的代码,大家都很熟悉,测试跑monkey出现了NullPointerException,看log发现竟然是调用Handler.yyy()方法出现的空指针。
mHandler.yyy();出现了空指针问题。
按照我菜鸟的理解感觉不可思议,明明做了为空判断,怎么还发生了空指针?
随着开发经验的累积,这种情况多发生在多线程操作同一个对象的情况下,并且发生概率极低,很难复现。
如果测试跑monkey出现了空指针问题,遇到这样的bug如何解决呢?
synchronized (锁对象) {
if (mHandler != null) {
mHandler.xxx();
mHandler.yyy();
}
}
相信很多开发的朋友都会用上面的方法解决这个空指针的问题,当然只要是用了同步,包括同步方法或者同步代码块都算是同一类解决方案。
后来有幸得到大神指点,学到了另外一种解决方案。
Handler handler = mHandler;
if (handler != null) {
handler.xxx();
handler.yyy();
}
将mHandler赋值给一个局部变量handler,对局部变量handler进行为空判断,之后用handler调用方法。
这种方案可以解决同步带来的性能问题。
这种解法让我想到了android源码中有类似的代码,当时感觉还很不理解,感觉多此一举。为什么不直接使用成员变量而是赋值给一个局部变量后,再使用局部变量呢?
赋值给局部变量之后,方法栈中局部变量持有的对象会有一份副本,在成员变量被赋值为null时,局部变量持有的对象不会受影响。