57. 【Android教程】相机:Camera

2024-05-09 04:44
文章标签 android 教程 相机 camera 57

本文主要是介绍57. 【Android教程】相机:Camera,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

相机现在已经不仅仅是手机必备神器了,甚至相机的拍照质量已经是很多人买手机的首选条件了。而对于相机而言主要有两大功能:拍照片和拍视频。Android 为此两种方式:

  • 相机 intent
  • 相机 API
    本节我们就一起来看看相机的具体用法。

1. 打开 Camera 的两大方式

目前市面上绝大多数的 Android 手机是有前后两个摄像头,当然有部分特殊机型会存在其他的情况,本节主要针对双摄像头设备做解析。
在前面有提到过,通常使用相机有两大方式:“Intent”和“API”。最大的差别就是“Intent”是跳转到系统提供的相机页面,而使用“API”是封闭在自己的 App 中使用相机。我们可以通过“Intent”直接打开系统提供的相机 Activity,在用户拍摄完成之后系统 Activity 会通知我们拍摄结果,然后拿到拍摄的图片或者视频。而直接通过 API 就需要我们去开发一整套相机的控制页面,自行完成照片 / 视频的拍摄进而直接拿到用户拍摄的结果。

2. Camera 的基本用法

我们分别看看这两种打开方式的使用方法:

2.1 使用 Intent 打开

通过使用 MediaStore 类提供的两个 Intnet 常量,可以直接将相机操作托管给 Android 系统而无需创建 Camera 实例:

  • ACTION_IMAGE_CAPTURE:
    拍摄照片
  • ACTION_VIDEO_CAPTURE:
    拍摄视频

2.2 使用 API 打开

采用 API 打开会让整个相机程序都封闭在自己的 APP 中完成,这里需要明确几个概念:

  1. Camera 类
    使用 API 之前需要创建 Camera 实例,然后通过 API 来初始化 Camera 进而拿到实时拍摄的画面

  2. SurfaceView
    用来渲染视频实时画面的 View

采用 Intent 打开相机的方法非常简单,接下来我们全程使用 Camera API 来实现一下相机功能。

3. Camera 使用示例

使用 API 来拍照会相对比较麻烦一点,首先需要获取权限,那么对于 Android 6.0 版本以上的系统除了要在 Manifest 里面加入 Camera 权限之外,还需要动态获取权限,这个可能大家在用一些比较老的教程示例时会踩坑。
获取到权限就可以打开 Camera 了,然后拿到 Camera 实例设置一个 SurfaceView 来渲染预览页面,在用户需要拍照的时候调用 Camera 的takePicture()方法获取当前帧,最后保存输出到文件中或者在新的 Activity 中展示,这样就算完成了一次拍照闭环。

3.1 Camera 拍照逻辑

首先看看整个拍照的代码如下:


package com.emercy.myapplication;import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;public class MainActivity extends Activity {public static final String CAMERA_PATH = "path";public static final String CAMERA_IMG = "img";private SurfaceView mSurfaceView;private Button mTakePhoto;private Camera mCamera = null;private SurfaceHolder.Callback mCallback = new SurfaceHolder.Callback() {@Overridepublic void surfaceCreated(SurfaceHolder holder) {startPreview();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {stopPreview();}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getPermission();bindViews();}/*** 获取权限*/private void getPermission() {if (Build.VERSION.SDK_INT > 22) {if (checkSelfPermission(android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {//先判断有没有权限 ,没有就在这里进行权限的申请requestPermissions(new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);} else {//说明已经获取到摄像头权限了Log.i("Camera", "已经获取了权限");}} else {//这个说明系统版本在6.0之下,不需要动态获取权限。Log.i("Camera", "这个说明系统版本在6.0之下,不需要动态获取权限。");}}private void bindViews() {mSurfaceView = (SurfaceView) findViewById(R.id.sfv_preview);mTakePhoto = (Button) findViewById(R.id.btn_take);mSurfaceView.getHolder().addCallback(mCallback);mTakePhoto.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mCamera.takePicture(null, null, new Camera.PictureCallback() {@Overridepublic void onPictureTaken(byte[] data, Camera camera) {String path;if (TextUtils.isEmpty(path = savePhoto(data))) {Intent it = new Intent(MainActivity.this, PreviewActivity.class);it.putExtra(CAMERA_PATH, path);startActivity(it);} else {Toast.makeText(MainActivity.this, "拍照失败", Toast.LENGTH_SHORT).show();}}});}});}private String savePhoto(byte[] bytes) {try {File file = File.createTempFile(CAMERA_IMG, "");FileOutputStream fos = new FileOutputStream(file);fos.write(bytes);fos.flush();fos.close();return file.getAbsolutePath();} catch (IOException e) {e.printStackTrace();}return "";}private void startPreview() {mCamera = Camera.open();try {mCamera.setPreviewDisplay(mSurfaceView.getHolder());mCamera.setDisplayOrientation(90);   // 让相机旋转90度mCamera.startPreview();} catch (IOException e) {e.printStackTrace();}}private void stopPreview() {mCamera.stopPreview();mCamera.release();mCamera = null;}
}

里面涉及到的几个新概念大家需要注意,然后记得在SurfaceHolder.Callback()surfaceCreated()中启动预览,在surfaceDestroyed()方法中要停止预览,其他的基本上按照步骤来不会有什么问题。

3.2 相机布局

目前市面上有很多相机 App,各种布局千变万化,大家完全可以按照自己的喜好来进行设计。这里只做一个拍照预览和拍照按钮。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><SurfaceViewandroid:id="@+id/sfv_preview"android:layout_width="match_parent"android:layout_height="match_parent" /><Buttonandroid:id="@+id/btn_take"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="bottom|center"android:text="拍照" /></FrameLayout>

3.3 照片回看页面

点击“拍照” Button 获取到当前画面之后,我们可以就可以按照自己的逻辑对图片进行操作了。比如可以通过 Http 上传、通过 Socket 发送给其他设备、保存到本地、或者传递给其他 App 等。本例子中将图片传递给另一个 Activity 专门用于查看图片,下面是 PhotoActivity 的代码:

package com.emercy.myapplication;import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.widget.ImageView;import java.io.File;import static com.emercy.myapplication.MainActivity.CAMERA_PATH;public class PhotoActivity extends Activity {@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);ImageView img = new ImageView(this);String path = getIntent().getStringExtra(CAMERA_PATH);if (path != null) {img.setImageURI(Uri.fromFile(new File(path)));}setContentView(img);}
}

通过 Intent 接收图片路径,然后展示在 ImageView 上,需要注意的是PhotoActivity 中是直接将 ImageView 作为参数直接设置给了 SetContentView(),这样相当于布局文件中只有一个 ImageView 的写法。

最后别忘了在 Manifest 当中添加权限:

    <uses-permission android:name="android.permission.CAMERA"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

编译运行效果如下:

点击拍照进入 PhotoActivity,展示的就是我们拍照的画面。

4. 小结

本节学习了一个手机上必不可少的设备,通过相机我们可以拍摄照片或者视频,Android 系统提供了两大打开方式:Intent 调用系统相机 Activitiy或者用 Camera API 自行实现拍照功能。第一种非常简单,将所有的相机操作都托管给系统,我们只关心最终用户拍摄的结果;而第二种就需要我们自己初始化 Camera 对象从而实现拍摄,在实际开发中如果你的功能是和拍摄强相关,需要一些定制化的拍摄体验,那么一定要使用第二种方式来自己实现 Camera,但是如果你只是一个简单的拍照获取图片,那么第一种会让你事半功倍。

这篇关于57. 【Android教程】相机:Camera的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/972426

相关文章

springboot使用Scheduling实现动态增删启停定时任务教程

《springboot使用Scheduling实现动态增删启停定时任务教程》:本文主要介绍springboot使用Scheduling实现动态增删启停定时任务教程,具有很好的参考价值,希望对大家有... 目录1、配置定时任务需要的线程池2、创建ScheduledFuture的包装类3、注册定时任务,增加、删

Android使用ImageView.ScaleType实现图片的缩放与裁剪功能

《Android使用ImageView.ScaleType实现图片的缩放与裁剪功能》ImageView是最常用的控件之一,它用于展示各种类型的图片,为了能够根据需求调整图片的显示效果,Android提... 目录什么是 ImageView.ScaleType?FIT_XYFIT_STARTFIT_CENTE

如何为Yarn配置国内源的详细教程

《如何为Yarn配置国内源的详细教程》在使用Yarn进行项目开发时,由于网络原因,直接使用官方源可能会导致下载速度慢或连接失败,配置国内源可以显著提高包的下载速度和稳定性,本文将详细介绍如何为Yarn... 目录一、查询当前使用的镜像源二、设置国内源1. 设置为淘宝镜像源2. 设置为其他国内源三、还原为官方

Android实现在线预览office文档的示例详解

《Android实现在线预览office文档的示例详解》在移动端展示在线Office文档(如Word、Excel、PPT)是一项常见需求,这篇文章为大家重点介绍了两种方案的实现方法,希望对大家有一定的... 目录一、项目概述二、相关技术知识三、实现思路3.1 方案一:WebView + Office Onl

Android实现两台手机屏幕共享和远程控制功能

《Android实现两台手机屏幕共享和远程控制功能》在远程协助、在线教学、技术支持等多种场景下,实时获得另一部移动设备的屏幕画面,并对其进行操作,具有极高的应用价值,本项目旨在实现两台Android手... 目录一、项目概述二、相关知识2.1 MediaProjection API2.2 Socket 网络

Maven的使用和配置国内源的保姆级教程

《Maven的使用和配置国内源的保姆级教程》Maven是⼀个项目管理工具,基于POM(ProjectObjectModel,项目对象模型)的概念,Maven可以通过一小段描述信息来管理项目的构建,报告... 目录1. 什么是Maven?2.创建⼀个Maven项目3.Maven 核心功能4.使用Maven H

Android实现悬浮按钮功能

《Android实现悬浮按钮功能》在很多场景中,我们希望在应用或系统任意界面上都能看到一个小的“悬浮按钮”(FloatingButton),用来快速启动工具、展示未读信息或快捷操作,所以本文给大家介绍... 目录一、项目概述二、相关技术知识三、实现思路四、整合代码4.1 Java 代码(MainActivi

Android Mainline基础简介

《AndroidMainline基础简介》AndroidMainline是通过模块化更新Android核心组件的框架,可能提高安全性,本文给大家介绍AndroidMainline基础简介,感兴趣的朋... 目录关键要点什么是 android Mainline?Android Mainline 的工作原理关键

IDEA自动生成注释模板的配置教程

《IDEA自动生成注释模板的配置教程》本文介绍了如何在IntelliJIDEA中配置类和方法的注释模板,包括自动生成项目名称、包名、日期和时间等内容,以及如何定制参数和返回值的注释格式,需要的朋友可以... 目录项目场景配置方法类注释模板定义类开头的注释步骤类注释效果方法注释模板定义方法开头的注释步骤方法注

如何解决idea的Module:‘:app‘platform‘android-32‘not found.问题

《如何解决idea的Module:‘:app‘platform‘android-32‘notfound.问题》:本文主要介绍如何解决idea的Module:‘:app‘platform‘andr... 目录idea的Module:‘:app‘pwww.chinasem.cnlatform‘android-32