调用相机
根据我微薄的安卓开发经验,直接给你们源文件会出各种各样的兼容性问题,所有我把需要使用的文件内容分类放置,你们逐个复制粘贴即可。
这里有我之前的错误案例以及一些log,还有更改后的分析。希望对你有帮助,如果可以请给我一个评论或赞,这是我持续上传笔记的动力。
前面部分是我根据网上的各种教程写的程序,会出一些错误,我对此进行了分析和改错。不想看的朋友可以直接跳转到“修改后”。
[[#layout]]
[[#mainActivity.java]]
[[#AndroidManifest.xml]]
[[#@xml/paths]]
[[#log以及报错问题]]
layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/take_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="take it">
<ImageView
android:id="@+id/photo"
android:layout_width="0dp"
android:layout_height="145dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
//布局使用了constratlayout,使用了一个按钮控件和一个,imageView控件,imageView控件没有设置图片
mainActivity.java
import 内容省略
package com.example.tackemac;
public class MainActivity extends AppCompatActivity {
public static final int TAKE_PHOTO = 1;
private ImageView picture;
private Uri imageUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//onCreate 函数重写,绑定mainactivity.
Button takePhoto = (Button) findViewById(R.id.take_photo);
picture = (ImageView) findViewById(R.id.photo);
//控件ID绑定
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.e(TAG,"onclickstart");
File outputImage = new File(getExternalCacheDir(),
"output_image.jpg");
//点击事件
// IO流,将图片存储到output_image.jpg中
//CacheDir–外部缓存地址
try {
if (outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
//捕获异常,检测是否存在相同照片
//检测SDK版本,做不同版本的适配↓
if (Build.VERSION.SDK_INT >= 24) {
Log.e(TAG,"onclickif");
imageUri = FileProvider.getUriForFile(MainActivity.this,
"com.exanple.cameraablumtest.flieprovider",
outputImage);
} else {
imageUri = Uri.fromFile(outputImage);
}
Log.e(TAG,"newintent");
//跳转到系统相机中
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
Log.e(TAG,"intent");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
// MainActivity.this.startActivityForResult(intent,TAKE_PHOTO);
startActivityForResult(intent, TAKE_PHOTO);
}
});
}
/*==重写onActivityResult结果函数
request Code --启动活动请求,用于区分是哪个请求的结果
result Code --返回结果, result_OK标示成功。
Intent data --返回跳转的对象
Bitmap–一种照片图像数据的表示形式
BitmaoFactory.decodeStream --把获取的图片解码为bitmap图
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.e(TAG,"onActiviyResult");
switch (requestCode) {
case TAKE_PHOTO:
if (resultCode == RESULT_OK) {
try {
Bitmap bitmap = BitmapFactory.decodeStream(
getContentResolver().openInputStream(imageUri));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
default:
break; }
} }
AndroidManifest.xml
获取的照相和存储权限
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.tackemac"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!--声明访问SD卡权限↑-->
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Tackemac"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:authorities="com.example.bicameralism.file-provider"
android:name="androidx.core.content.FileProvider"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
<!-- 请注意这里-->
android:resource="@xml/file_paths"/>
</provider>
</application>
</manifest>
指定Uri共享路径,@xml/paths
@xml/paths
在res中新建一个xml文件夹,再在其中新建一个名为file_path.xml的文件
<?xml version="1.0" encoding="utf-8"?>
<paths
xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="my_images"
path="output_image.jpg"/>
</paths>
<‘external-path’>指定Uri共享,path表示具体路径,空值表示整个SD卡共享,这里仅共享ouput_image.jpg的路径
log以及报错问题
E avc: denied { find } for service=netd pid=7894 uid=2000 scontext=u:r:shell:s0 tcontext=u:object_r:netd_service:s0 tclass=service_manager
2024-10-14 19:40:05.070 1369-1369 SELinux servicemanager E avc: denied { find } for service=android.service.gatekeeper.IGateKeeperService pid=7894 uid=2000 scontext=u:r:shell:s0 tcontext=u:object_r:gatekeeper_service:s0 tclass=service_manager
2024-10-14 19:40:05.076 1369-1369 SELinux servicemanager E avc: denied { find } for service=installd pid=7894 uid=2000 scontext=u:r:shell:s0 tcontext=u:object_r:installd_service:s0 tclass=service_manager
2024-10-14 19:40:07.315 1700-1910 JavaBinder
system_server
E !!! FAILED BINDER TRANSACTION !!! (parcel size = 108)
//怀疑是传输问题,但是没有找到解决方法
==E !!! FAILED BINDER TRANSACTION !!! (parcel size = 108)
//怀疑是传输问题,但是没有找到解决方法
//android似乎对图片传输大小有限制,看网上的各种方法没有完全理解
2024-10-14 19:40:08.106 7938-7962 <no-tag> com.example.tackemac D HostConnection::get() New Host Connection established 0xa2c76140, tid 7962
2024-10-14 19:40:10.572 1369-1369 SELinux servicemanager E avc: denied { find } for service=netd pid=7966 uid=2000 scontext=u:r:shell:s0 tcontext=u:object_r:netd_service:s0 tclass=service_manager
2024-10-14 19:40:10.574 1369-1369 SELinux servicemanager E avc: denied { find } for service=android.service.gatekeeper.IGateKeeperService pid=7966 uid=2000 scontext=u:r:shell:s0 tcontext=u:object_r:gatekeeper_service:s0 tclass=service_manager
2024-10-14 19:40:10.575 1369-1369 SELinux servicemanager E avc: denied { find } for service=installd pid=7966 uid=2000 sconte
修改后
maiActivity.java
定义常量
/*
Oncreate函数绑定布局
定义常量
request_image_caputue =1 – 请求图像捕捉;
REQUEST_CAMERA_PERMISSION = 100 --请求相机许可
*/
public class MainActivity extends AppCompatActivity {
static final int REQUEST_IMAGE_CAPTURE = 1;
static final int REQUEST_CAMERA_PERMISSION = 100;
Oncreate函数绑定布局
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
定义常量
/*
定义常量
request_image_caputue =1 – 请求图像捕捉;
REQUEST_CAMERA_PERMISSION = 100 --请求相机许可
*/
public void takePictureIntent(View view) {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
} else {
dispatchTakePictureIntent();
}
}
点击事件
/*
点击事件!
判断是否拥有相机权限,如果没有就请求相机权限,如果有就使用Intent打开相机。
GRANTED --授予
if中
ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED
为授予权限的判定
*/
请求使用相机
public void dispatchTakePictureIntent(){
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
try {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
} catch (ActivityNotFoundException e) {
// display error state to the user
Log.e("WarningMsg","相机打开失败!");
}
}
/*
使用Intent打开相机↑dispatchTakePictureIntent()
这个名为dispatchTakePictureIntent
的方法主要用于启动设备的相机应用以拍摄照片。
----
传入一个请求码REQUEST_IMAGE_CAPTURE
。当相机应用拍摄完照片后,结果会返回到调用这个方法的活动(Activity)中,通过重写onActivityResult
方法可以处理拍摄后的照片数据。
------
如果在尝试启动相机的过程中抛出了ActivityNotFoundException
异常,说明设备上没有能够响应这个拍照意图的应用程序。此时会捕获这个异常,并在日志中打印错误信息“相机打开失败!”,
*/
请求认证
/*
----
==请求认证回调函数,public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)请求权限成功之后,再次回调打开相机
- `requestCode`:用于区分不同的权限请求。这里通过与常量`REQUEST_CAMERA_PERMISSION`比较,确定是否是相机权限请求的结果。
permissions`:一个字符串数组,包含被请求的权限名称。
- `grantResults`:一个整数数组,对应`permissions`数组中的权限请求结果,`PackageManager.PERMISSION_GRANTED`表示权限被授予,`PackageManager.PERMISSION_DENIED`表示权限被拒绝。==↓
*/
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
dispatchTakePictureIntent();//打开相机
} else {
Toast.makeText(this, "无法获取拍照权限", Toast.LENGTH_SHORT).show(); }
} }
把内容传入imageView
/*
==在拍照完成后,激活该方法,把照片数写入ImageView
protected void onActivityResult(int requestCode, int resultCode, Intent data)
- requestCode
:用于区分不同的启动子活动的请求码。在这个例子中,通过与特定的常量REQUEST_IMAGE_CAPTURE
进行比较,确定返回的结果是否来自相机拍照的请求。
—
resultCode
:表示子活动的返回结果状态码。这里通过与RESULT_OK
进行比较,确定拍照操作是否成功。
----
-Intent data
:子活动返回的包含数据的意图(Intent)对象。
----
- 使用findViewById(R.id.iv)
找到一个ImageView
控件,然后通过imageView.setImageBitmap(imageBitmap)
将拍摄的照片设置为这个ImageView
的显示内容。↓↓
==
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
ImageView imageView = findViewById(R.id.iv);
imageView.setImageBitmap(imageBitmap);
}
}
[返回标题](#调用相机)
### AndroidMainfest.xml
==权限添加==
```xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />