我一直在挣扎了一会儿打造ScanResult
对象。我已经成功地使用了上面的反射方法。
如果某人正在寻找一种方式来克隆ScanResult
对象(或实现Parcelable
接口的任何其他物体),你可以用这个方法(我查了一下它的权利在单元测试):
@RunWith(RobolectricTestRunner.class)
@Config(manifest=Config.NONE)
public class MovingAverageQueueTests {
@Test
public void parcelTest() {
Parcel parcel = Parcel.obtain();
ScanResult sr = buildScanResult("01:02:03:04:05:06", 70);
parcel.writeValue(sr);
parcel.setDataPosition(0); // required after unmarshalling
ScanResult clone = (ScanResult)parcel.readValue(ScanResult.class.getClassLoader());
parcel.recycle();
assertThat(clone.BSSID, is(equalTo(sr.BSSID)));
assertThat(clone.level, is(equalTo(sr.level)));
assertThat(clone, is(not(sameInstance(sr))));
}
private ScanResult buildScanResult(String mac, int level) {
Constructor<ScanResult> ctor = null;
ScanResult sr = null;
try {
ctor = ScanResult.class.getDeclaredConstructor(null);
ctor.setAccessible(true);
sr = ctor.newInstance(null);
sr.BSSID = mac;
sr.level = level;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return sr;
}
}
至于性能方面,这款天真检查:
@Test
public void buildVsClonePerformanceTest() {
ScanResult sr = null;
long start = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
sr = buildScanResult("01:02:03:04:05:06", 70);
}
long elapsedNanos = System.nanoTime() - start;
LOGGER.info("buildScanResult: " + elapsedNanos);
start = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
sr = cloneScanResult(sr);
}
elapsedNanos = System.nanoTime() - start;
LOGGER.info("cloneScanResult: " + elapsedNanos);
}
展示了这些结果:
2016年10月26日下午3时25分19秒com.example.neutrino.maze.MovingAverageQueueTests buildVsClonePerformanceTest 信息:buildScanResult: 2016年10月26日下午3点25分21秒com.example.neutrino.maze.MovingAverageQueueTests buildVsClonePerformanceTest 信息:cloneScanResult:
所以克隆这种方式是10倍以上,即使反射创建实例效果较差。我知道这个测试并不稳健,因为在编译时优化已经完成......但是十的因素很难减轻。我也测试了10K次迭代,然后系数甚至达到了100!只是为了您的信息。
P.S.让Parcel.obtain()和parcel.recycle走出循环没有帮助
围绕测试需求设计似乎很奇怪。包装我可能需要使用的每个系统api是否还有其他好处? – Brian 2011-04-09 23:29:15
@Brian是的。首先你可以在一个地方交换WifiManager。版本x出来后会发生什么,并且API有所不同?您必须更改代码库中的很多区域。我更新了更多信息的答案。 – Finglas 2011-04-10 11:49:29
啊,是的,隔离可能改变的东西。除非我用抽象来保护自己,否则我无法控制Android API。好决定! – Brian 2011-04-10 14:38:42