IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 创新实训项目分析——第六篇 -> 正文阅读

[移动开发]创新实训项目分析——第六篇

2021SC@SDUSC


前言

上几篇文章已经分析完了飞花令的项目,从这一篇开始分析camera的项目。开发人员的设计中,以手机相机为依托的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类二者结合去处理首选项参数的问题,看到一篇有关于相机参数的文章,结合开发人员的注释,感觉学到了很多东西。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-11-12 19:42:39  更:2021-11-12 19:43:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:08:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码