最近在开发系统的相机应用,今天发现一个奇怪的BUG,Camera.java里面报的一个关于LinkedHashMap的空指针的错误。。。
java.lang.NullPointerException: Attempt to write to field 'java.util.LinkedHashMap$LinkedEntry java.util.LinkedHashMap$LinkedEntry.prv' on a null object reference
at java.util.LinkedHashMap.postRemove(LinkedHashMap.java:292)
at java.util.HashMap.remove(HashMap.java:629)
at android.hardware.Camera$Parameters.put(Camera.java:4139)
at android.hardware.Camera$Parameters.set(Camera.java:4119)
at android.hardware.Camera$Parameters.setColorEffect(Camera.java:4876)
at com.xxx.camera.c.a.c(DynamicFilterManager.java:148)
at com.xxx.camera.c.a.f(DynamicFilterManager.java:158)
at com.xxx.camera.o.br(CamModule.java:3392)
at com.xxx.camera.o.l(CamModule.java:2193)
at com.xxx.camera.o.aQ(CamModule.java:706)
at com.xxx.camera.o.t(CamModule.java:91)
at com.xxx.camera.o$n.run(CamModule.java:3283)
这。。。很明显不是APP的锅。。。看了代码就是在AsyncTask里面调了一个方法而已。。。难道真的是AsyncTask有毒吗!?相关的代码如下:
new AsyncTaskEx<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
//...省略
mParamsManager.getParams().setColorEffect(filterName);
mParamsManager.setParameters();
return null;
}
}.execute();
参考了下面这篇文章之后:
http://longyi-java.iteye.com/blog/1678574
得出的结论如下:
- Camera对象中含有一个内部类Camera.Parameters。厂商可以针对该类,可以对Camera的特性进行定制。
- 在Parameters中设置完成后,需要调用Camera.setParameters()方法,相应的设置才会生效。
- 由于不同的设备,Camera的特性是不同的,所以在设置时,需要首先判断设备对应的特性,再加以设置。比如在调用setColorEffects之前最好先调用getSupportedColorEffects。如果设备不支持颜色特性,那么该方法的调用将抛出一个空指针异常。
下面继续分析Camera的setColorEffect方法:
public void setColorEffect(String value) {
set(KEY_EFFECT, value);
}
setColorEffect实际调用了set方法:
public void set(String key, String value) {
if (key.indexOf('=') != -1 || key.indexOf(';') != -1 || key.indexOf(0) != -1) {
Log.e(TAG, "Key \"" + key + "\" contains invalid character (= or ; or \\0)");
return;
}
if (value.indexOf('=') != -1 || value.indexOf(';') != -1 || value.indexOf(0) != -1) {
Log.e(TAG, "Value \"" + value + "\" contains invalid character (= or ; or \\0)");
return;
}
put(key, value);
}
然后是put方法:
private void put(String key, String value) {
/*
* Remove the key if it already exists.
*
* This way setting a new value for an already existing key will always move
* that key to be ordered the latest in the map.
*/
mMap.remove(key);
mMap.put(key, value);
}
这里我们可以看到,mMap就是一个LinkedHashMap,就是我们需要分析的目标。在进行put操作之前,先执行了remove(key),由于不同厂商定制的Camera不一样,这个key在原生Camera中是这样的:
private static final String KEY_EFFECT = "effect";
但是,定制过之后的机器可能就不是这个值了,例如下面的filter-mode,虽然一般的厂商不会这样干。下面是我自己的解决办法,就是根不同据机器设置不同的值:
if (DeviceHelper.DEVICE_IS_XXX) {
mParamsManager.getParams().set("filter-mode", filterName);
}
另外,在设置Camera的setParameters之前,最好先判断一下机器的支持属性,例如本例子中的ColorEffects的设置:
List<String> supportedColorEffects = mParamsManager.getParams().getSupportedColorEffects();
if (supportedColorEffects.contains(filterName)) {
mParamsManager.getParams().setColorEffect(filterName);
}
最后,我想说的是,AsyncTask我错怪你了,不过AsyncTask的坑切实很多,鉴于老项目喜欢用这个,因此有时间的话还是有必要去学习研究一下AsyncTask。
如果觉得我的文字对你有所帮助的话,欢迎关注我的公众号:
公众号:Android开发进阶我的群欢迎大家进来探讨各种技术与非技术的话题,有兴趣的朋友们加我私人微信huannan88,我拉你进群交(♂)流(♀)。
网友评论