当前位置: 首页 > news >正文

【Android入门到项目实战-- 7.3】—— 如何调用手机摄像头和相册

目录

一、调用摄像头拍照

二、打开相册选择照片


        学完本篇文章可以收获如何调用手机的摄像头和打开手机相册选择图片功能。

一、调用摄像头拍照

先新建一个CameraAlbumTest项目。

修改activity_main.xml,代码如下:

        按钮打开摄像头,ImageView将拍到的图片显示出来。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/take_photo"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="打开摄像头"/><ImageViewandroid:id="@+id/picture"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"/></LinearLayout>

下面编写调用摄像头的具体逻辑,修改MainActivity代码,如下:

        按钮点击事件里首先创建一个File对象,用于存放摄像头拍下的照片,并命名为output_image.jpg,并将它存放在手机SD卡的应用关联缓存目录下(SD卡中专门存放当前应用缓存数据的位置),调用getExternalCacheDir()方法可以得到这个目录,目录具体路径是:/sdcard/Android/data/包名/cache。

        放入缓存目录下的目的是可以不需要处理运行时权限。

        接着进行一个判断,如果Android版本低于7.0,调用Uri的fromFile()方法将File对象转换成Uri对象。否则,将File对象转换为Uri对象,Uri对象标识着output_image.jpg这张图片的本地真实路径。这里使用FileProvider的getUriForFile()方法转换为Uri对象,此方法有3个参数,第一个是Context对象,第二个是任意唯一的字符串,第三个是刚刚创建的File对象。

        之所以进行转换,是因为直接使用本地真实路径Uri被认为是不安全的,会抛出异常,而FileProvider是一种特殊的内容提供器,它使用了和内容提供其类似的机制来对数据进行保护,可以选择性将封装过的Uri共享给外部,提高了安全性。

        接下来构建Intent对象,调用putExtra()方法指定图片的输出地址,这里填入的是刚刚得到的Uri对象,最后调用startActivityForResult()来启动活动,拍下的照片输出到output_image.jpg中。

        由于使用的是startActivityForResult()来启动活动,因此拍完照后结果会返回到onActivityResult()方法中,就可以调用BitmapFactory的decodeStream()方法将照片解析成Bitmap对象,然后设置到ImageView中显示出来。

public class MainActivity extends AppCompatActivity {public static final int TAKE_PHOTO = 1;private ImageView picture;private Uri imageUri;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button takePhoto = (Button) findViewById(R.id.take_photo);picture = (ImageView) findViewById(R.id.picture);takePhoto.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {
//                创建File对象,用于存储拍照后的照片File outputImage = new File(getExternalCacheDir(),"output_image.jpg");try {if(outputImage.exists()){outputImage.delete();}outputImage.createNewFile();}catch (IOException e){e.printStackTrace();}if(Build.VERSION.SDK_INT >= 24){imageUri = FileProvider.getUriForFile(MainActivity.this,"com.example.cameraalbumtest.fileprovider",outputImage);}else{imageUri = Uri.fromFile(outputImage);}
//                启动相机Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);startActivityForResult(intent,TAKE_PHOTO);}});}protected void onActivityResult(int requestCode,int resultCode,Intent data) {super.onActivityResult(requestCode, resultCode, data);switch (requestCode) {case TAKE_PHOTO:if (resultCode == RESULT_OK) {try {
//                        显示拍摄的照片Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));picture.setImageBitmap(bitmap);} catch (FileNotFoundException e) {e.printStackTrace();}}break;default:break;}}
}

然后在res目录下新建一个名字为xml的目录(如果有则忽略这步),右键xml目录 -> New -> File,创建一个file_paths.xml文件,修改内容,代码如下:

        external-path用来指定Uri共享,name属性值随意填,path属性的值表示共享的具体路径,这里设置空值表示将整个SD卡共享,也可以仅共享我们存放output_image.jpg这张图片的途径。

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"><external-pathname="my_images" path=""/>
</paths>

最后修改AndroidManifest.xml文件代码,如下:

        由于刚才使用了内容提供器,所以需要进行注册。

        需要声明访问SD卡的权限。

        android:name值是固定的,android:authorities的值必须要和刚才的FileProvider.getUriForFile()方法中的第二个参数的值一致,<meta-data>指定Uri的共享路径。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"package="com.example.cameraalbumtest"><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"..........<providerandroid:authorities="com.example.cameraalbumtest.fileprovider"android:name="androidx.core.content.FileProvider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_paths"/></provider>...................

 

效果如下:

二、打开相册选择照片

        在以上项目的基础上进行修改。

        修改activity_main.xml文件,在布局中添加一个按钮用于从相册中选择照片,如下:

...................<Buttonandroid:id="@+id/choose_from_album"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="选择照片"/>
...................

        修改MainActivity代码,如下:

        代码稍微有点长,因为对Android4.4以上和以下版本分别做了处理,如果你的应用不希望版本低的使用,那么可以不用处理4.4以下版本。

public class MainActivity extends AppCompatActivity {public static final int TAKE_PHOTO = 1;private ImageView picture;private Uri imageUri;public static final int CHOOSE_PHOTO = 2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button takePhoto = (Button) findViewById(R.id.take_photo);Button chooseFromAlbum = (Button) findViewById(R.id.choose_from_album);picture = (ImageView) findViewById(R.id.picture);takePhoto.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {
//                创建File对象,用于存储拍照后的照片File outputImage = new File(getExternalCacheDir(),"output_image.jpg");try {if(outputImage.exists()){outputImage.delete();}outputImage.createNewFile();}catch (IOException e){e.printStackTrace();}if(Build.VERSION.SDK_INT >= 24){imageUri = FileProvider.getUriForFile(MainActivity.this,"com.example.cameraalbumtest.fileprovider",outputImage);}else{imageUri = Uri.fromFile(outputImage);}
//                启动相机Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);startActivityForResult(intent,TAKE_PHOTO);}});chooseFromAlbum.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {if(ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);}else{openAlbum();}}});}private void openAlbum(){Intent intent = new Intent("android.intent.action.GET_CONTENT");intent.setType("image/*");startActivityForResult(intent,CHOOSE_PHOTO);//打开相册}public void onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults){
super.onRequestPermissionsResult(requestCode, permissions, grantResults);switch (requestCode){case 1:if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){openAlbum();}else{Toast.makeText(this, "你拒绝了权限申请", Toast.LENGTH_SHORT).show();}break;default:}}protected void onActivityResult(int requestCode,int resultCode,Intent data) {super.onActivityResult(requestCode, resultCode, data);switch (requestCode) {case TAKE_PHOTO:if (resultCode == RESULT_OK) {try {
//                        显示拍摄的照片Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));picture.setImageBitmap(bitmap);} catch (FileNotFoundException e) {e.printStackTrace();}}break;case CHOOSE_PHOTO:if(resultCode == RESULT_OK){
//                    判断手机系统版本号if(Build.VERSION.SDK_INT >= 19){
//                        4.4及以上系统使用这个方法处理图片handleImageOnKitKat(data);}else{
//                        4.4以下用这个方法handleImageBeforeKitKat(data);}}break;default:break;}}@TargetApi(19)private void handleImageOnKitKat(Intent data) {String imagePath = null;Uri uri = data.getData();Log.d("TAG", "handleImageOnKitKat: uri is " + uri);if (DocumentsContract.isDocumentUri(this, uri)) {// 如果是document类型的Uri,则通过document id处理String docId = DocumentsContract.getDocumentId(uri);if("com.android.providers.media.documents".equals(uri.getAuthority())) {String id = docId.split(":")[1]; // 解析出数字格式的idString selection = MediaStore.Images.Media._ID + "=" + id;imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);} else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));imagePath = getImagePath(contentUri, null);}} else if ("content".equalsIgnoreCase(uri.getScheme())) {// 如果是content类型的Uri,则使用普通方式处理imagePath = getImagePath(uri, null);} else if ("file".equalsIgnoreCase(uri.getScheme())) {// 如果是file类型的Uri,直接获取图片路径即可imagePath = uri.getPath();}displayImage(imagePath); // 根据图片路径显示图片}private void handleImageBeforeKitKat(Intent data) {Uri uri = data.getData();String imagePath = getImagePath(uri, null);displayImage(imagePath);}@SuppressLint("Range")private String getImagePath(Uri uri, String selection) {String path = null;// 通过Uri和selection来获取真实的图片路径Cursor cursor = getContentResolver().query(uri, null, selection, null, null);if (cursor != null) {if (cursor.moveToFirst()) {path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));}cursor.close();}return path;}private void displayImage(String imagePath) {if (imagePath != null) {Bitmap bitmap = BitmapFactory.decodeFile(imagePath);picture.setImageBitmap(bitmap);} else {Toast.makeText(this, "failed to get image", Toast.LENGTH_SHORT).show();}}
}

        最后提醒一下,因为有些照片尺寸很大,直接加载到内存中会导致程序崩溃,需要根据需求对照片进行压缩,再加载到内存中。

相关文章:

【Android入门到项目实战-- 7.3】—— 如何调用手机摄像头和相册

目录 一、调用摄像头拍照 二、打开相册选择照片 学完本篇文章可以收获如何调用手机的摄像头和打开手机相册选择图片功能。 一、调用摄像头拍照 先新建一个CameraAlbumTest项目。 修改activity_main.xml,代码如下&#xff1a; 按钮打开摄像头&#xff0c;ImageView将拍到的…...

浅聊AIOT

引言 IoT是(Internet of Things)的简称&#xff0c;也就是人们常说的物联网&#xff1b;随着智能硬件的发展和推广&#xff0c;制造成本也随之下降&#xff0c;很多的厂家也慢慢地拥抱网络互联&#xff0c;逐步实现设备互联&#xff0c;也就进入了人们常说的万物互联时代。虽然…...

Python之模块和包(九)

1、模块 1、模块概述 模块是一个包含了定义的函数和变量等的文件。模块可以被程序引入&#xff0c;以使用该模块中的函数等功能。通俗讲&#xff1a;模块就好比是工具包&#xff0c;要想使用这个工具包中的工具(就好比函数)&#xff0c;就需要导入这个模块。 2、import 在P…...

C++-----动态规划

目录 一、动态规划的基本思想 二、设计动态规划法的步骤 三、动态规划问题的特征 4.1 矩阵连乘积问题 4.1.1 分析最优解的结构 4.1.2 建立递归关系 4.1.3 计算最优值 4.1.3 计算最优值 4.1.3 构造最优解 4.2 动态规划算法的基本要素 4.2.1 最优子结构 4.2.2 重叠子问题 …...

2.2 Linux控制台访问CLI

系列文章目录 第1章 Linux Shell简介 第2章 Shell基础 <本章所在位置> 第3章 Bash Shell基础命令 第4章 Bash Shell命令进阶 第5章 Linux Shell深度理解 第6章 Linux环境变量 第7章 Linux文件权限 第8章 Linux文件系统的管理 第9章 Linux软件安装 第10章 Linux文本编辑器…...

代码随想录补打卡 509 斐波那契数列

代码如下 //斐波那契数列的第0项是0 第一项是1 func fib(n int) int { if n < 1 { return n } dp : make([]int,n1) dp[0] 0 dp[1] 1 for i : 2 ; i < n ; i { dp[i] dp[i-1] dp[i-2] } return dp[n] } 70 爬楼梯 代码如下 func climbStairs(n int) int …...

【每日一题Day195】LC1003检查替换后的词是否有效 | 栈

检查替换后的词是否有效【LC1003】 给你一个字符串 s &#xff0c;请你判断它是否 有效 。 字符串 s 有效 需要满足&#xff1a;假设开始有一个空字符串 t "" &#xff0c;你可以执行 任意次 下述操作将 t 转换为 s &#xff1a; 将字符串 "abc" 插入到 t…...

简单理解什么是序列化

为什么要序列化 序列化的目的就是为了对象可以在网络层进行传输&#xff0c; 比如通过后端传给前端数据。 什么是序列化 我们以Java为例。 序列化就是把对象转化为可传输的字节序列过程&#xff0c;这个字节序列可以是字符串&#xff0c;比如JSON格式的字符串&#xff0c;把…...

Django初识

1、简介 Django&#xff0c;是用python语言写的开源web开发框架&#xff0c;并遵循MVC设计。劳伦斯出版集团为了开发以新闻内容为主的网站&#xff0c;而开发出来了这个框架&#xff0c;于2005年7月在BSD许可证下发布。这个名称来源于比利时的爵士音乐家DjangoReinhardt&#…...

ARM嵌入式编译器-volatile关键字对编译器优化的影响

volatile限定符告知计算机&#xff0c;其他agent&#xff08;而不是变量所在的程序&#xff09;可以改变该变量的值。通常它被用于硬件地址以及在其他程序或同时运行的线程中共享数据。要求编译器不要对其描述的对象作优化处理&#xff0c;对它的读写都需要从内存中访问。 使用…...

销售数据分析怎么做?这篇文章说清楚了

如何分析销售数据&#xff1f;分析销售数据有哪些指标&#xff1f;销售数据分析有什么作用&#xff1f; 销售数据是不是得通过数据分析软件啊&#xff1f; 本文将为您解答疑惑—— 一、分析销售数据的指标 从两个层面上来讲&#xff0c;一个是对销售情况的整体把控&#xf…...

二十六、ISIS技术总结

文章目录 ISIS 概述一、路由协议总结1、路由优先级2、分类 二、ISIS 协议特点1、特点2、ISIS 路由器的种类 三、ISIS 配置1、基础配置2、network-entity含义3、router id 和系统id转换规则 四、ISIS 开销计算1、Narrow 模式2、Wide 模式 五、 ISIS 和 OSPF 的区别 ISIS 概述 I…...

三菱m70 m80系统解密 三菱m80机床到期解锁

我们从操作系统的发展讲起&#xff0c;为什么要有线程这个概念出现。《Java多线程学习笔记(一) 初遇篇》讲Java平台下的线程&#xff0c;如何使用和创建&#xff0c;以及引入线程后所面临的问题&#xff0c;为了解决线程安全问题&#xff0c;Java引入的机制&#xff0c;这也是《…...

InnoDB 磁盘结构之数据字典和双写缓冲区

数据字典&#xff08;InnoDB Data Dictionary&#xff09; MySQL中&#xff0c;数据字典包括了: 表结构、数据库名或表名、字段的数据类型、视图、索引、表字段信息、MySQL版本信息、存储过程、触发器等内容 InnoDB数据字典由内部系统表组成&#xff0c;这些表包含用于查找表…...

Django模型层part two - 多表关系创建和多表操作

前言 继续上面一篇文章的内容&#xff0c;本文介绍多表操作。使用django ORM可以创建多表关系&#xff0c;并且也支持多张表之间的操作&#xff0c;以创建表关系和查询两部分说明django ORM的多表操作。以作者、图书、出版社和作者信息几张表作为案例进行说明。 创建表关系 …...

智能优化算法:浣熊优化算法-附代码

智能优化算法&#xff1a;浣熊优化算法 文章目录 智能优化算法&#xff1a;浣熊优化算法1.浣熊优化算法1.1 初始化1.2 阶段一&#xff1a;狩猎和攻击&#xff08;探索阶段&#xff09; 2.实验结果3.参考文献4. Matlab 摘要&#xff1a;浣熊优化算法&#xff08;Coati Optimizat…...

【51单片机】数码管显示(样例展示以及异常分析)

🎊专栏【51单片机】 🍔喜欢的诗句:更喜岷山千里雪 三军过后尽开颜。 🎆音乐分享【如愿】 大一同学小吉,欢迎并且感谢大家指出我的问题🥰 ⭐数码管 比如要显示“6”,那么下面图片中,AFEDCG=1,B=0 对应到数码管上,就是 ⭐原理 🎊P22~P24控制LED1~...

Android InputChannel事件发送接收系统分析

本文基于Android12。 InputChannel表示其他进程通过文件描述符传递输入事件到View的通道&#xff0c;因为需要跨进程传输&#xff0c;实现了Parcelable序列化接口&#xff0c;所以也能够理解Java层的InputChannel后面为什么使用copyTo()方法初始化。 输入事件的接收方是View&…...

Java时间类(五)-- LocalDate()类

目录 引言: 1. LocalDate的概述: 2. LocalDate的常用方法: 引言: (1)Date存在的缺陷: 如果不格式化,打印出的日期可读性差://获取当前时间Date date = new Date();System.out.println("date = " + date); //date = Wed May 03 22:30:24 CST...

用手机号码归属地 API 开发的应用推荐

引言 手机号码归属地 API是一种提供手机号码归属地信息的接口&#xff0c;通过该接口&#xff0c;可以获取手机号码所属的省份、城市、运营商等信息。它可以帮助企业更好地了解客户&#xff0c;为个性化推荐和精准广告投放提供数据支持。作为一种数据服务&#xff0c;手机号码…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...