一、使用照相功能
调用安卓的照相功能,需要隐式发起Activity,当然要取得拍照后的照片是需要一个到达照片的路径的,那么这个路径被放在Uri中,这就需要取得路径的Uri。为了兼容新版本,其中使用了文件的内容提供器,那么就需要配置内容提供器同时还在指定存储拍照后的照片的SD卡路径,值得注意的是Android4.4之前读取SD卡相关的路径需要权限的,为了兼容是需要加上SD卡权限。
package com.lht.liuhaitao;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
public class MainActivity extends Activity {
static final String TAG="MainActivity";
private Button but;
private ImageView imageView;
private Uri imageUri;
public static final int TAKE_PHOTO=1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
but=findViewById(R.id.but_ok);
imageView=findViewById(R.id.pothoImg);
but.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
capture();
}
});
}
private void capture(){
try {
//读写SD卡是危险权限,使用SD卡中缓存目录可以避免运行时权限判断,省事
File outfFile=new File(getExternalCacheDir(),"output_image.jpg");
if(outfFile.exists()){
outfFile.delete();
}
outfFile.createNewFile();
if(Build.VERSION.SDK_INT>=24){
//这是个特殊内容提供器FileProvider,因为在Android7后觉得直接用真实路径的Uri不安全,所以用这个内容提供其
//用内容提供器就要一会去配置的,第二个参数是什么无所谓但是必须与配置文件中的android:authorities值一致
imageUri=FileProvider.getUriForFile(this,"com.lht.liuhaitao.xxxprovider",outfFile);
}else{
imageUri=Uri.fromFile(outfFile);
}
Intent intent=new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
startActivityForResult(intent,TAKE_PHOTO);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
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));
imageView.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
}
}
}
xml目录是自己新建的
<provider
android:authorities="com.lht.liuhaitao.xxxprovider"
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths">
</meta-data>
</provider>
file_paths.xml 用来定义照相机的存储路径
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_imgs" path=""/>
</paths>
二、读取相册照片
package com.lht.liuhaitao;
import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
public class MainActivity extends Activity {
static final String TAG="MainActivity";
private Button but;
private ImageView imageView;
public static final int TAKE_PHOTO=1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
but=findViewById(R.id.but_ok);
imageView=findViewById(R.id.pothoImg);
but.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
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();
}
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case 1:
if(permissions.length>=0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
openAlbum();
}else{
Log.e(TAG, "onRequestPermissionsResult: 没有权限" );
finish();
}
break;
}
}
private void openAlbum(){
Intent intent=new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
startActivityForResult(intent,TAKE_PHOTO);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode){
case TAKE_PHOTO:
if(resultCode==RESULT_OK){
//判断手机系统版本号
if(Build.VERSION.SDK_INT>=19){
Bitmap bitmap=handleImageOnKitKat(this,data);
imageView.setImageBitmap(bitmap);
}else{
//handleImageOnKitKat(this,data);
Bitmap bitmap=handleImageBeforeKitKat(this,data);
imageView.setImageBitmap(bitmap);
}
}
break;
}
}
//4.4及以上系统使用这个方法处理图片
@TargetApi(19)
public static Bitmap handleImageOnKitKat(Context context, Intent data) {
String imagePath = null;
Uri uri = data.getData();
if (DocumentsContract.isDocumentUri(context, uri)) {
//如果是document类型的Uri,则通过document id处理
String docId = DocumentsContract.getDocumentId(uri);
if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
String id = docId.split(":")[1]; //解析出数字格式的id
String selection = MediaStore.Images.Media._ID + "=" + id;
imagePath = getImagePath(context, 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(context, contentUri, null);
}
} else if ("content".equalsIgnoreCase(uri.getScheme())) {
//如果不是document类型的Uri,则使用普通方式处理
imagePath = getImagePath(context, uri, null);
}
return getImage(imagePath);
}
//4.4以下系统使用这个方法处理图片
public static Bitmap handleImageBeforeKitKat(Context context, Intent data) {
Uri uri = data.getData();
String imagePath = getImagePath(context, uri, null);
return getImage(imagePath);
}
public static String getImagePath(Context context, Uri uri, String selection) {
String path = null;
//通过Uri和selection来获取真实的图片路径
Cursor cursor = context.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;
}
//对bitmap进行质量压缩
public static Bitmap compressImage(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
int options = 100;
while (baos.toByteArray().length / 1024 > 100) { //循环判断如果压缩后图片是否大于100kb,大于继续压缩
baos.reset();//重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
options -= 10;//每次都减少10
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片
return bitmap;
}
//传入图片路径,返回压缩后的bitmap
public static Bitmap getImage(String srcPath) {
if (TextUtils.isEmpty(srcPath)) //如果图片路径为空 直接返回
return null;
BitmapFactory.Options newOpts = new BitmapFactory.Options();
//开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);//此时返回bm为空
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
//现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
float hh = 800f;//这里设置高度为800f
float ww = 480f;//这里设置宽度为480f
//缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
int be = 1;//be=1表示不缩放
if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0)
be = 1;
newOpts.inSampleSize = be;//设置缩放比例
//重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
return compressImage(bitmap);//压缩好比例大小后再进行质量压缩
}
}
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>