(来自《第一行代码》)
调用摄像头拍照和从相册中选择照片是很多应用软件有的功能。下面是基本功能的实现:
布局很简单:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/btn_take_photo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="点我拍照" />
<Button
android:id="@+id/btn_choose_photo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="选择照片" />
<ImageView
android:id="@+id/iv_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@drawable/ic_launcher" />
</LinearLayout>
然后是具体的逻辑(全部写在一个Activity里了):
package com.example.camera;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ContentUris;
import android.content.Intent;
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.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.MediaStore.Images.Media;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends Activity {
public static final int TAKE_PHOTO = 1;
public static final int CROP_PHOTO = 2;
public static final int CHOOSE_PHOTO = 3;
private Button mButtonTake, mButtonChoose;
private ImageView mImageView;
private Uri mImgUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.iv_img);
mButtonTake = (Button) findViewById(R.id.btn_take_photo);
mButtonChoose = (Button) findViewById(R.id.btn_choose_photo);
mButtonChoose.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
// 打开相册
startActivityForResult(intent, CHOOSE_PHOTO);
}
});
mButtonTake.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 创建File对象,用于存储拍照后的图片,并存放在SD卡的根目录下
File outputImg = new File(Environment.getExternalStorageDirectory(), "my_img.jpg");
if (outputImg.exists()) {
outputImg.delete();
}
try {
outputImg.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
// 将File对象转换为Uri对象
mImgUri = Uri.fromFile(outputImg);
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
// 指定图片的输出地址
intent.putExtra(MediaStore.EXTRA_OUTPUT, mImgUri);
// 启动相机程序
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) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(mImgUri, "image/*");
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mImgUri);
// 启动裁剪程序
startActivityForResult(intent, CROP_PHOTO);
}
break;
case CROP_PHOTO:
if (resultCode == RESULT_OK) {
try {
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(mImgUri));
// 将裁剪后的照片显示出来
mImageView.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);
}
}
default:
break;
}
}
/**
* 4.4以上系统处理图片的方法(Android系统从4.4开始选取相册中的图片不再返回真实地Uri,而是一个封装过的Uri)
*
* @param data
*/
@TargetApi(19)
private void handleImageOnKitKat(Intent data) {
String imagePath = null;
Uri uri = data.getData();
// 如果是document类型的Uri,则通过document id处理
if (DocumentsContract.isDocumentUri(this, uri)) {
String docId = DocumentsContract.getDocumentId(uri);
if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
// 解析出数字格式的Id
String id = docId.split(":")[1];
String 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())) {
// 如果不是document类型的Uri,则用普通方式处理
imagePath = getImagePath(uri, null);
}
displayImage(imagePath);
}
/**
* 4.4以下系统处理图片的方法
*
* @param data
*/
private void handleImageBeforeKitKat(Intent data) {
Uri uri = data.getData();
String imagePath = getImagePath(uri, null);
displayImage(imagePath);
}
/**
* 根据图片路径选择图片
*
* @param imagePath
* 图片路径
*/
private void displayImage(String imagePath) {
if (imagePath != null) {
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
mImageView.setImageBitmap(bitmap);
} else {
Toast.makeText(MainActivity.this, "获取图片失败", Toast.LENGTH_SHORT).show();
}
}
/**
* 通过uri和selection来获取真实地图片路径
*
* @param uri
* 资源索引
* @param selection
* 查询符合条件的过滤参数,类似于SQL语句中Where之后的条件判断
* @return
*/
private String getImagePath(Uri uri, String selection) {
String path = null;
Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
path = cursor.getString(cursor.getColumnIndex(Media.DATA));
}
cursor.close();
}
return path;
}
}
不要忘了权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
当然,还有很多优化的地方,以后慢慢补充。比如压缩,图形图像处理等等。