项目Http框架基于OkHttp二次封装
影响程度 >> 在弱网情况下异步请求接口时快速关闭页面必现
★★★★
Bug发现手段 >> Monkey测试
测试环境
- Android平台手机一台
- 网络限速为2G
- Monkey测试
手工测试为何没发现?
- Monkey测试有一种尽快跑完种子的机制,容易出现打开一个页面(Activity)后马上关闭
- 手工测试一般不会打开一个页面又马上关闭,故较难发现
报错信息
java.lang.NullPointerException: Attempt to invoke interface method
'void com.y.http.async.RequestListener.onComplete(java.lang.String, int)' on a null object reference
at com.y.http.async.HttpRequest$1.handleMessage(HttpRequest.java:42)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5438)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:629)
问题排查
- 同步请求 >> 正常
- 异步请求 >> 正常
- 异步请求网络差 >> 正常
- 异步请求网络差 + Listener销毁 >> 空指针异常
原因解析
在异步请求时Callback等待服务器返回数据,此时Activity被用户关闭,Listener在Activity的onDestroy方法被回收,待服务器返回数据时,Callback回调给监听器Listener。Listener调用onComplete()方法回调给Activity作数据处理,由于此时Listener为空,所以调用listener.onComplete()方法报错。
@Override
protected void onDestroy() {
super.onDestroy();
if (listener != null) {
listener = null;
}
}
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case HANDLER_SUCCESS:
int taskId = msg.arg1;
String result = (String)msg.obj;
listener.onComplete(result, taskId);
break;
case HANDLER_EXCEPTION:
taskId = msg.arg1;
BaseException e = (BaseException)msg.obj;
listener.onException(e, taskId);
break;
case HANDLER_CANCEL:
listener.onCancel();
break;
default:
break;
}
}
解决方案
在异步请求Callback回调给Listener,Listener调用方法前判空即可(由于此时Activity已经销毁,所以Listener为空,直接return是可行的)。
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if (listener == null) {
return;
}
switch (msg.what) {
case HANDLER_SUCCESS:
int taskId = msg.arg1;
String result = (String)msg.obj;
listener.onComplete(result, taskId);
break;
case HANDLER_EXCEPTION:
taskId = msg.arg1;
BaseException e = (BaseException)msg.obj;
listener.onException(e, taskId);
break;
case HANDLER_CANCEL:
listener.onCancel();
break;
default:
break;
}
}
验证代码
用修改后的Http框架导入项目,实测问题没有再发生。
测试关注点
多留意弱网情况下的测试。