在7.0以前,调用相机拍照
/**
* 拍照
*
* @param view
*/
@Event(R.id.btn_photo)
private void takePhoto(View view) {
//启动照相机拍照
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
photoPath = Environment.getExternalStorageDirectory() + "/xyh.jpg";
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(photoPath)));
startActivityForResult(intent, PHOTO_REQUEST);
}
在用Android 7.0版本时,出现了异常 FileUriExposedException,就是在传递uri时出错
百度了一下,说是Android 7.0后又修改了文件权限,可以使用FileProvider解决
1.在 res 目录下新建文件夹 xml 然后创建资源文件 filepaths(随意名字)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--external-path:代表的根目录: Environment.getExternalStorageDirectory()-->
<external-path
name="images"
path="拍照/" /> //存放照片文件夹
</resources>
<files-path/> //代表的根目录: Context.getFilesDir()
<external-path/> //代表的根目录: Environment.getExternalStorageDirectory()
<cache-path/> //代表的根目录: getCacheDir()
2.在manifest中添加provider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.xiaoyehai.takephoto.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
exported:要求必须为false,为true则会报安全异常。grantUriPermissions:true,表示授予 URI 临时访问权限。
3.调用相机拍照,图片得存储吧,存储图片又需要权限,因此动态申请权限
AndroidManifest.xml文件中:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
4.java代码
/**
* android7.0拍照
*/
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_PERMISSION_CODE = 559;
private static final int REQUEST_CAMERA = 648;
private ImageView mImageView;
private String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
private File mFile;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.iv);
}
public void doclick(View view) {
if (Build.VERSION.SDK_INT >= 23) {
if (ContextCompat.checkSelfPermission(this, permissions[0]) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSION_CODE);
} else {
takePhoto();
}
} else {
takePhoto();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_PERMISSION_CODE && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
takePhoto();
} else {
// 没有获取 到权限,从新请求,或者关闭app
Toast.makeText(this, "需要存储权限", Toast.LENGTH_SHORT).show();
}
}
private void takePhoto() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
mFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/拍照/" + System.currentTimeMillis() + ".jpg");
if (!mFile.getParentFile().exists()) {
mFile.getParentFile().mkdirs();
}
//改变Uri com.xiaoyehai.takephoto.fileprovider注意和清单文件中一致中的一致
Uri uri = FileProvider.getUriForFile(this, "com.xiaoyehai.takephoto.fileprovider", mFile);
//添加权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, REQUEST_CAMERA);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CAMERA && resultCode == RESULT_OK) {
Uri uri = FileProvider.getUriForFile(this, "com.xiaoyehai.takephoto.fileprovider", mFile);
//content://com.xiaoyehai.takephoto.fileprovider/images/1533796434054.jpg
Log.e("xyh", "onActivityResult: " + uri);
mImageView.setImageBitmap(BitmapFactory.decodeFile(mFile.getAbsolutePath()));
//在手机相册中显示刚拍摄的图片
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(mFile);
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);
}
}
}
如果图片太大,会造成OOM,可以对图片进行压缩
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CAMERA && resultCode == RESULT_OK) {
Uri uri = FileProvider.getUriForFile(this, "com.xiaoyehai.takephoto.fileprovider", mFile);
//content://com.xiaoyehai.takephoto.fileprovider/images/1533796434054.jpg
Log.e("xyh", "onActivityResult: " + uri);
//如果图片太大,可以对图片进行压缩
Bitmap bitmap = BitmapUtils.compressBitmap(mFile.getAbsolutePath(), mImageView.getMeasuredWidth(), mImageView.getMeasuredHeight());
mImageView.setImageBitmap(bitmap);
//在手机相册中显示刚拍摄的图片
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(mFile);
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);
}
}
BitmapUtils
package com.xiaoyehai.takephoto;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;
import java.io.ByteArrayOutputStream;
/**
* Created by xiaoyehai on 2018/3/2 0002.
*/
public class BitmapUtils {
/**
* Base64字符串转换成图片
*
* @param string
* @return
*/
public static Bitmap stringtoBitmap(String string) {
Bitmap bitmap = null;
try {
byte[] bitmapArray;
bitmapArray = Base64.decode(string, Base64.DEFAULT);
bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.length);
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
/**
* 图片转换成Base64字符串
*
* @param bitmap
* @return
*/
public static String bitmaptoString(Bitmap bitmap) {
//将Bitmap转换成字符串
String string = null;
ByteArrayOutputStream bStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bStream);
byte[] bytes = bStream.toByteArray();
string = Base64.encodeToString(bytes, Base64.DEFAULT);
return string;
}
/**
* 对资源文件中的图片进行压缩
*
* @param context 上下文对象
* @param imageId 压缩图片的id
* @param destWidth 显示图片的控件宽度
* @param destHeight 显示图片的控件高度
* @return
*/
public static Bitmap compressBitmap(Context context, int imageId, int destWidth, int destHeight) {
//创建一个可选项对象,该对象用于配置图片的处理参数
BitmapFactory.Options options = new BitmapFactory.Options();
//第一次采样,该属性设置为true只会加载图片的边框进来,并不会加载图片具体的像素点,也就是说不会把图片加载到内存中
options.inJustDecodeBounds = true;
//加载图片,该方法只是从图片文件中读取图片的宽和高信息,而没有真正的加载到内存中
BitmapFactory.decodeResource(context.getResources(), imageId, options);
//获取图片的宽和高
int imageWidth = options.outWidth;
int imageHeight = options.outHeight;
//定义缩放比例
int sampleSize = 1;
while (imageWidth / sampleSize > destHeight || imageHeight / sampleSize > destWidth) {
//如果宽高的任意一方的缩放比例没有达到要求,都继续增大缩放比例
//sampleSize应该为2的n次幂,如果给sampleSize设置的数字不是2的n次幂,那么系统会就近取值
sampleSize *= 2;
}
//第二次采样,使用缩放比例进行缩放加载图,加载器就会返回图片了
options.inJustDecodeBounds = false;
//设置压缩比
options.inSampleSize = sampleSize;
/**
* inPreferredConfig设置图片的质量:
* ARGB_8888:默认的图片质量,也是最好的质量,32位,4个字节
* ARGB_4444:是ARGB_8888占用内存的一半,但质量比较低,16位,不推荐使用
* RGB_565:不带透明度,是ARGB_8888占用内存的一半,质量不错,16位,推荐使用
* ALPHA_8:
*/
//设置图片质量
options.inPreferredConfig = Bitmap.Config.RGB_565;
//返回压缩后的图片
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), imageId, options);
//Log.i("info", "压缩后图片的大小:" + bitmap.getByteCount());
return bitmap;
}
/**
* 对内存卡中的图片进行压缩
*
* @param path 图片路径
* @param destWidth 显示图片的控件宽度
* @param destHeight 显示图片的控件高度
* @return
*/
public static Bitmap compressBitmap(String path, int destWidth, int destHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
int imageWidth = options.outWidth;
int imageHeight = options.outHeight;
int sampleSize = 1;
while (imageWidth / sampleSize > destHeight || imageHeight / sampleSize > destWidth) {
sampleSize *= 2;
}
options.inJustDecodeBounds = false;
options.inSampleSize = sampleSize;
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
//Log.i("info", "压缩后图片的大小:" + bitmap.getByteCount());
return bitmap;
}
/**
* 通过网络请求返回的字节数据进行二次采样并返回bitmap
*
* @param bytes
* @param destWidth 显示图片的控件宽度
* @param destHeight 显示图片的控件高度
* @return
*/
public static Bitmap compressBitmap(byte[] bytes, int destWidth, int destHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
int imageWidth = options.outWidth;
int imageHeight = options.outHeight;
int sampleSize = 1;
while (imageWidth / sampleSize > destHeight || imageHeight / sampleSize > destWidth) {
sampleSize *= 2;
}
options.inJustDecodeBounds = false;
options.inSampleSize = sampleSize;
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
// Log.i("info", "压缩后图片的大小:" + bitmap.getByteCount());
return bitmap;
}
}