美文网首页
关于Camera$Parameters的BUG历险记

关于Camera$Parameters的BUG历险记

作者: 小楠总 | 来源:发表于2017-08-02 17:30 被阅读274次

    最近在开发系统的相机应用,今天发现一个奇怪的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
    

    得出的结论如下:

    1. Camera对象中含有一个内部类Camera.Parameters。厂商可以针对该类,可以对Camera的特性进行定制。
    2. 在Parameters中设置完成后,需要调用Camera.setParameters()方法,相应的设置才会生效。
    3. 由于不同的设备,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,我拉你进群交(♂)流(♀)

    相关文章

      网友评论

          本文标题:关于Camera$Parameters的BUG历险记

          本文链接:https://www.haomeiwen.com/subject/idjylxtx.html