最近学习安卓拍照部分的知识,其中遇到不少的坑,看视频学习,照着视频里面的代码敲,代码一毛一样,可是我的就是总是出现各种各样的问题,真的是烦~
捣鼓了两三天终于搞好了。
废话不多说。
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/preView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:orientation="horizontal"
android:padding="20dp">
<Button
android:id="@+id/takephoto"
android:layout_width="80dp"
android:layout_height="80dp"
android:padding="20dp"
android:background="@drawable/takephoto" />
LinearLayout>
RelativeLayout>
java文件 SystemCameraActivity.java
package com.exercise03.testapp;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.StrictMode;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
//调用系统相机
public class SystemCameraActivity extends AppCompatActivity{
private Button takePhoto;
private ImageView preView;
private File capturedPhoto = null;
private Uri fileUri = null;
private final int REQUEST_CODE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_system_camera);
//严格模式
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
builder.detectFileUriExposure();
//绑定控件
preView = (ImageView)findViewById(R.id.preView);
takePhoto = (Button)findViewById(R.id.takephoto);
//设置takePhoto按钮监听事件
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//将文件保存在SD卡中
File dir = new File(Environment.getExternalStorageDirectory(),"SystemCamera");
if(!dir.exists()){
dir.mkdirs();
}
//照片文件名
String capturePhotoName = System.currentTimeMillis() + ".jpg";
capturedPhoto = new File(dir,capturePhotoName);
//判断该文件是否存在
if(!capturedPhoto.exists()){
//创建这个文件
try {
capturedPhoto.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
//step1:调用系统相机 (隐式 Intent)
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri = Uri.fromFile(capturedPhoto);
intent.putExtra(MediaStore.EXTRA_OUTPUT,fileUri);
//step2: 启用intent
startActivityForResult(intent,REQUEST_CODE);
}
});
}
//step3: 重写方法
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//将拍照得到的照片添加到ImageView中
if(requestCode == REQUEST_CODE){
fileUri = Uri.fromFile(capturedPhoto);
preView.setImageURI(fileUri);
Toast.makeText(this, "图片已加载到ImageView中", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(this, "图片加载失败", Toast.LENGTH_SHORT).show();
}
}
}
写调用系统相机的代码中遇到这样的问题
问题1:
之前是使用xml文件的onClick属性调用方法,结果一直显示
java.lang.IllegalStateException: Could not find method systemCamera(View)
in a parent or ancestor Context for android:onClick attribute defined on
view class android.widget.Button with id 'takephoto' at
android.view.View$DeclaredOnClickListener.resolveMethod
让后百度得到的结果是可能xml文件的布局嵌套得太深的问题,所以我改成了设置监听的方式调用方法
解决了这个问题
问题2:
android.os.FileUriExposedException:
file:///storage/emulated/0/Android/data/com.yuyh.imgsel/
cache/1486438962645.jpg exposed beyond app through
ClipData.Item.getUri()
原因
主要是由于在Android 7.0以后,用了Content Uri 替换了原本的File Uri, * 故在targetSdkVersion=24的时候,部分 “Uri.fromFile() “
方法就不适用了。 * File Uri 与 Content Uri 的区别 - File Uri 对应的是文件本身的存储路径 - Content Uri * 对应的是文件在Content Provider的路径 * 所以在android 7.0 以上,我们就需要将File Uri转换为 Content Uri。
解决方法:在onCreate方法中加入以下代码即可解决
//严格模式
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
builder.detectFileUriExposure();
问题3:
调用系统相机拍的照片无法加载到ImageView中
这个问题很奇怪,我在网上看到if(requestCode == REQUEST_CODE)
这个判断语句是这样的if(requestCode == REQUEST_CODE && requestCode == REQUEST_OK)
,还有看视频教程里也是这样的,但是我把&& requestCode == REQUEST_OK
删掉后就可把照片加载到ImageView中了。
==分割线
xml布局文件:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:orientation="horizontal"
android:padding="20dp">
<Button
android:id="@+id/takephoto"
android:layout_width="80dp"
android:layout_height="80dp"
android:padding="20dp"
android:background="@drawable/takephoto" />
LinearLayout>
RelativeLayout>
java文件 CustomCameraActivity.java
看图
package com.exercise03.testapp;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class CustomCameraActivity extends AppCompatActivity {
//step1:设置各种所需要的变量
private Camera camera; //定义相机对象
private boolean isPreview = false; //定义非预览状态
private SurfaceView surfaceView;
private Button takePhoto;
String photoPath = "/DCIM/Camera/"; //照片文件存储路径
//这个也是一个变量,只是很长而已
private SurfaceHolder.Callback SurfaceHolder_Callback = new SurfaceHolder.Callback(){
@Override
public void surfaceCreated(SurfaceHolder holder) {
startPreview(); //开始预览
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
stopPreview(); //停止预览
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_camera);
//设置全屏显示
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
/*//这个好像没什么用了,因为现在大多数手机都不装SD卡了
if (!Environment.getExternalStorageState().equals( //判断手机是否安装SD卡
Environment.MEDIA_MOUNTED)) {
Toast.makeText(this, "请安装SD卡!", Toast.LENGTH_SHORT).show(); // 提示安装SD卡
}
*/
//step2:
//获取SurfaceView组件,用于显示相机预览
surfaceView = (SurfaceView)findViewById(R.id.surfaceView);
//获取SurfaceHolder对象
final SurfaceHolder surfaceHolder = surfaceView.getHolder();
//设置该SurfaceHolder自己不维护缓冲
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceHolder.addCallback(SurfaceHolder_Callback);//刚刚那个很长的变量用在这里了
//获取Button组件,用于拍照
takePhoto = (Button)findViewById(R.id.takephoto);
takePhoto.setOnClickListener(new View.OnClickListener() {//设置按钮监听事件
@Override
public void onClick(View v) {
if(camera != null){
camera.takePicture(null,null,Camera_PictureCallback);
Toast.makeText(CustomCameraActivity.this, "照片已保存在" + photoPath + "中", Toast.LENGTH_SHORT).show();
}
}
});
}
//step3: 实现将照片保存到系统图库中
final Camera.PictureCallback Camera_PictureCallback = new Camera.PictureCallback(){
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// 根据拍照所得的数据创建位图
Bitmap bitmap = BitmapFactory.decodeByteArray(data,0,data.length);
camera.stopPreview(); //停止预览
isPreview = false; //设置为非预览状态
//获取sd卡根目录
File dir = new File(Environment.getExternalStorageDirectory(),photoPath);
if(!dir.exists()){ //如果该目录不存在
dir.mkdirs(); //就创建该目录
}
//将获取当前系统时间设置为照片名称
String fileName = System.currentTimeMillis() + ".jpg";
//创建文件对象
File capturedPhoto = new File(dir,fileName);
try {
FileOutputStream fileOutputStream = new FileOutputStream(capturedPhoto);
bitmap.compress(Bitmap.CompressFormat.JPEG,100,fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
};
//开始预览,图像显示在SurfaceView中
public void startPreview(){
camera = Camera.open();
isPreview = true; //设置为预览状态
try {
camera.setPreviewDisplay(surfaceView.getHolder());
camera.setDisplayOrientation(90); //让相机旋转90度
camera.startPreview();
camera.autoFocus(null); //设置自动对焦
} catch (IOException e) {
e.printStackTrace();
}
}
//停止预览
public void stopPreview(){
camera.stopPreview();
camera.release();
camera = null;
}
@Override
protected void onPause() {
super.onPause();
if(camera != null){
camera.stopPreview();
camera.release();
}
}
}
这个到好像没遇到什么问题。
最后一定得把权限加上,在AndroidManifest.xml文件中加上下面的代码
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">uses-permission>
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
最后最后,打开APP前先要把相机权限和存储权限打开,不然APP会闪退
测试使用机型:小米8(android 9.0)