创新实训项目分析——第六篇

2021SC@SDUSC


前言

以手机相机为依托的camera项目不仅需要有基础的拍照功能,并且还需要对拍摄的照⽚进⾏⼀系列处理,包括但不仅限于图⽚抗扭曲,曝光度,聚焦等。具体可以整理为以下功能:
1. 相机预览功能
2. 拍照的偏好设置,如闪光灯,聚焦,曝光补偿
3. 相机可随设备旋转,拍摄横屏和竖屏的照⽚
4. 拍照后保存在⼿机的pictures⽂件夹
5. 可以预览拍摄的照⽚
6. 图⽚抗扭曲处理
这篇将继续分析相机的预览功能和偏好设置。

一、项目环境

android studio版本 4.1.2

sdk版本 Compile SDK version:30

Build Tools Version 30.0.3

gradle版本 6.8.3

二、代码分析

1.配置surface类

重写surfaceCreated方法,首先先用getCameraInstance()方法获得camera实例,setPreviewDisplay()方法告知mCamera实例应该在哪里绘制预览;

 public void surfaceCreated(SurfaceHolder holder) {
        mCamera = getCameraInstance();
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }
​

关于surfaceDestroyed()方法,在帮助文档中是:“ This is called immediately before a surface is being destroyed. After returning from this call, you should no longer try to access this surface. If you have a rendering thread that directly accesses the surface, you must ensure that thread is no longer touching the Surface before returning from this function.”这段话表明在surface在关闭之前立即调用,他与surfaceCreated()的关系可以概括为:当view处于可见状态时执行surfaceCreated(),不可见时执行surfaceDestoryed(),类似于c++中的构造函数和析构函数
在surfaceDestroyed()之中,removeCallback()删除了添加的关于surface变化的回调,二者解绑;而camera实例的setPrevireCallback()的作用是在视频预览过程中,每一帧的图像数据均会通过这个callback返回,此时设为null,才能够正确退出,这是必要的一步

    public void surfaceDestroyed(SurfaceHolder holder) {
        mHolder.removeCallback(this);
        mCamera.setPreviewCallback(null);
        mCamera.stopPreview();
        mCamera.release();//释放camera实例空间
        mCamera = null;
    }
​
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    }
}

并且在xml文件里需要加上:

<uses-permission android:name="android.permission.CAMERA" /> 
<uses-feature android:name="android.hardware.camera" />

获取到相机使用权限

2.相机功能设置

要实现相机的三个功能:聚焦,曝光补偿和闪光灯
在preference.xml里设计界面利用了ListPreference框架
ListPreference框架:
该框架为用户提供UI 来查看排序选项列表。该列表将包含每个选项的单选按钮,而且默认(或当前)选项应该被预先选中。要使用Android首选项框架解决此问题。首先,创建首选项XML文件来描述首选项,然后使用预先构建的活动类。

<ListPreference
    android:defaultValue="auto"
    android:key="flash_mode"
    android:title="闪光灯" />
<ListPreference
    android:key="focus_mode"
    android:title="对焦模式" />
<ListPreference
    android:defaultValue="0"
    android:key="exposure_compensation"
    android:title="曝光补偿" />

请添加图片描述

当选择其中某一个功能键时,会有两个视图。底视图称为首选项屏幕,中间的UI是一个列表首选项。当用户选择闪光灯或者对焦或者曝光补偿时时, UI视图将以模态对话框的形式出现,其中包含每个选项的单选按钮。用户选择一个选项之后,将立即该选项并关闭视图。当用户返回选项屏幕时,视图将反映前面保存的选择。

3.编写SettingsFragment类

开发人员使用Android推荐的PreferenceFragment作为相机偏好设置的菜单。PreferenceFragment继承自Fragment。有关于曝光补偿、闪光灯和聚焦的功能的实现,我们主要就是通过PreferenceFragment来实现的:Android专门为有多个参数的选项提供了便捷的基类PreferenceFragment,类内部封装了Preference,会帮我们自动读写设置,方便开发者便捷完成这类功能。
主要的步骤可以概括为:
在res中创建xml文件夹,文件夹中创建preference.xml文件(即2中的xml文件),创建PreferenceFragment的子类,在onCreate方法中调用addPreferencesFromResource方法加载xml目录下的资源即可
我们可以来看一下开发人员对此的编写:

1)定义SettringsFragment类

定义了SettringsFragment类,继承了PreferenceFragment父类,并且使用了SharedPreferences.OnSharedPreferenceChangeListener接口,用于监听首选项的变化

public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener{
 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);//添加首选项xml文件
        loadSupportedFlashMode();//加载闪光灯
        loadSupportedFocusMode();//加载聚焦
        loadSupportedExposeCompensation();//加载曝光补偿
    }
}

2)获取相机

我们使用CameraPreview中的相机

public static Camera getCameraInstance() {
        if (mCamera == null) {
            try {
                mCamera = Camera.open();
            } catch (Exception e) {
                Log.d(TAG, "camera is not available");
            }
        }
        return mCamera;
    }

然后我们将这个相机传入到SettingFragment中,用到的是passCamera()方法:mCamera用于存储传递过来的camera实例,mParameters用于存储camera实例的参数,passCamera()用来将相机传输给SettingsFragment。

  static Camera mCamera;
    static Camera.Parameters mParameters;
    public static void passCamera(Camera camera) {
        mCamera = camera;
        mParameters = camera.getParameters();
    }

然后在MainActivity中按钮监听之前添加

SettingsFragment.passCamera(cameraPreview.getCameraInstance());
向SettingsFragment传递来自camaraPreview的相机。

这样就做到了绑定相机的功能

3)设置曝光补偿

这是一个用来动态加载曝光补偿的方法,即和preference.xml中的曝光补偿相结合
代码如下:

private void stringListToListPreference(List<String> list, String key) {
        final CharSequence[] charSeq = list.toArray(new CharSequence[list.size()]);
        ListPreference listPref = (ListPreference) getPreferenceScreen().findPreference(key);
        listPref.setEntries(charSeq);
        listPref.setEntryValues(charSeq);
    }

CharSequence是一个描述字符串结构的接口,在这个接口里面一般发现有三种常用的子类
:String类
:StringBuffer类
:StringBuilder类
在该接口中有如下方法
:public char charAt​(int index);//获取指定索引的字符
:public int length​();//获取字符串长度
:public CharSequence subSequence​(int start, int end);//截取部分字符串

有关PreferenceScreen的使用可以参考文章:
https://blog.csdn.net/ZoeyZY/article/details/85128821
而方法getPreferenceScreen().findPreference()的作用则是获取由key指定的菜单条目,将其存储在listPref里面
再由setEntries()和setEntryValues向这个菜单条目指定用户可见的所有value和代码可见的所有value,就完成了对这个key条目的列表内容的动态加载。

静态成员变量KEY_PREF_PREV_SIZE存储预览分辨率的key(在preferences.xml定义)。
对于stringListToListPreference()的方法,其首先将List转换为CharSequence[];由getPreferenceScreen().findPreference()获取由key指定的菜单条目;由setEntries()和setEntryValues向这个菜单条目指定用户可见的所有value和代码可见的所有value,就完成了对这个key条目的列表内容的动态加载。

public static final String KEY_PREF_EXPOS_COMP = "exposure_compensation";
private void loadSupportedExposeCompensation() {
    int minExposComp = mParameters.getMinExposureCompensation();//得到相机参数返回来的相机所具有的最小曝光补偿参数
    int maxExposComp = mParameters.getMaxExposureCompensation();得到相机参数返回来的相机所具有的最大曝光补偿参数
    List<String> exposComp = new ArrayList<>();//创建一个String类型的List,用来存储所有曝光补偿的最小值和最大值的所有中间的值,由最低到最高形成一个List<String>
    for (int value = minExposComp; value <= maxExposComp; value++) {
        exposComp.add(Integer.toString(value));
    }
    stringListToListPreference(exposComp, KEY_PREF_EXPOS_COMP);
}

由mParameters.getMinExposureCompensation()获取相机支持的最低曝光补偿,mParameters.getMaxExposureCompensation()获取相机支持的最高曝光补偿,由最低到最高形成一个List,指定key后交给stringListToListPreference()就好了。

三、总结

开始处理预览和参数设置的问题了,初步了解了ListPreference框架和PreferenceFragment类二者结合去处理首选项参数的问题,看到一篇有关于相机参数的文章,结合开发人员的注释,感觉学到了很多东西。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值