相机已成为android手机不可或缺的一部分,我们在开发可能也会涉及到关于相机的使用,以及在使用中会遇到一些问题(重点),下面把我个人的一点经验贴出来,仅供大家参考学习。
最简单的方式直接调用系统相机进行拍照,虽然能满足拍照的要求,但拍照的功能和界面却局限系统相机的样子,于是我们这时根据Camera API实现自己的拍照和摄像程序,当然这并不是我想说重点,今天的重点在于开发中不同型号手机调用系统相机拍完照出现闪退的问题
一、调用安卓系统相机拍照
首先应该添加权限:
通过Intent 打开系统相机
openbButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 使用意图直接调用安装在手机上的照相机
Intent intent = new Intent(
android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
// 打开照相机,设置请求码
startActivityForResult(intent, OPEN_RESULT);
}
});
在onActivityResult中,通过相机返回意图intent.get("data") 取得拍照的图片
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OPEN_RESULT) {
if (resultCode == RESULT_OK) {
Bundle bundle = data.getExtras();
Bitmap bitmap = (Bitmap) bundle.get("data");
imageView.setImageBitmap(bitmap);
}
}
二.系统相机拍照方式---解决系统相机拍照闪退
上面的代码,实现了调用系统相机,但是经过我在测试数10台手机之后发现,红米和三星出现拍完照后返回时,黑屏闪退。测试结果说明,该方法只试用于部分手机。
观察错误信息,提示onActivityResult 中空指针异常,相机拍照返回的 Intent data这个参数为空无法取出刚刚拍照的Bitmap,研究了一下,应该是不同手机厂商在系统定制时,隐藏了拍照返回意图。厂商系统定制我们不能修改,只能采取另外的方式来保存照片。针对返回意图为空的问题,解决办法如下:
通过把照片保存在指定路径,完成后通过路径取出
takePhoto2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 调用系统相机
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
// 取当前时间为照片名
mPictureFile = DateFormat.format("yyyyMMdd_hhmmss",
Calendar.getInstance(Locale.CHINA))
+ ".jpg";
Log.d("onactivity", "mPictureFile:" + mPictureFile);
filePath = getPhotoPath() + mPictureFile;
// 通过文件创建一个uri中
Uri imageUri = Uri.fromFile(new File(filePath));
// 保存uri对应的照片于指定路径
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, OPEN_RESULT2);
}
});
拍照完成返回时,在onActivityResult中,通过指定文件的绝对路径,获得拍照的图片
if (requestCode == OPEN_RESULT2) {
if (resultCode == RESULT_OK) {
Log.e("takePhoto", filePath);
Bitmap bitmap = BitmapFactory.decodeFile(filePath);
// imageView.setImageURI(Uri.fromFile(new File(filePath)));
imageView.setImageBitmap(bitmap);
}
}
三、使用自定义路径拍照闪退问题
如果使用方法二拍照依然部分手机出现闪退的情况,观察打印的错误信息,依然NullPointerException,这个问题相对来说也比较简单,但第一次遇到也把我困住了一会,异常信息我就不贴出来了,错误的原因是这样的:
当我们 通过 startActivityForResult(intent, OPEN_RESULT); 打开系统相机时,部门手机由于系统优化的原因,会把当前页面的成员变量回收,当拍完照片返回时,在onActivityResult方法中是要通过照片路径来获得Bitmap,而这种情况下保存照片路径的mPictureFile指向的字符串已经被回收,mPictureFile值就为空,导致产生空指针异常而闪退。解决办法是在Activity中加上onSaveInstanceState生命周期方法,保证对象在被系统回收之前能够先以hashMap的形式保存下来,当返回时再从onRestoreInstanceState方法中恢复出来
下面把整个应用程序代码写出来,结合Activity的生命周期方法,可以更好的观察理解这个问题:
package cn.keno.takephoto;
import java.io.File;
import java.util.Calendar;
import java.util.Locale;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity {
private final String TAG = "TakePhoto";
private Button openbButton;
private Button takePhoto2; // 拍照2
private Button pickButton;
private ImageView imageView;
private String mPictureFile;
private String filePath;
private final int OPEN_RESULT = 1; // 打开相机
private final int PICK_RESULT = 2; // 查看相册
private final int OPEN_RESULT2 = 3; // 打开相机2
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "onCreate");
openbButton = (Button) findViewById(R.id.btnTakePhoto);
takePhoto2 = (Button) findViewById(R.id.btnTakePhoto2);
pickButton = (Button) findViewById(R.id.btnPick);
imageView = (ImageView) findViewById(R.id.imgPotho);
openbButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 使用意图直接调用安装在手机上的照相机
Intent intent = new Intent(
android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
// 打开照相机,设置请求码
startActivityForResult(intent, OPEN_RESULT);
}
});
takePhoto2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 调用系统相机
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
// 取当前时间为照片名
mPictureFile = DateFormat.format("yyyyMMdd_hhmmss",
Calendar.getInstance(Locale.CHINA))
+ ".jpg";
Log.d("onactivity", "mPictureFile:" + mPictureFile);
filePath = getPhotoPath() + mPictureFile;
// 通过文件创建一个uri中
Uri imageUri = Uri.fromFile(new File(filePath));
// 保存uri对应的照片于指定路径
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, OPEN_RESULT2);
}
});
pickButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 使用意图直接调用手机相册
Intent intent = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
// 打开手机相册,设置请求码
startActivityForResult(intent, PICK_RESULT);
}
});
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("filePath", filePath);
Log.d(TAG, "onSaveInstanceState");
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (TextUtils.isEmpty(filePath)) {
filePath = savedInstanceState.getString("filePath");
}
Log.d(TAG, "onRestoreInstanceState");
}
@Override
protected void onStart() {
super.onStart();
Log.i(TAG, "onStart");
}
@Override
protected void onRestart() {
super.onRestart();
Log.i(TAG, "onRestart");
}
@Override
protected void onResume() {
super.onResume();
Log.i(TAG, "onResume");
}
@Override
protected void onPause() {
super.onPause();
Log.i(TAG, "onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.i(TAG, "onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy");
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == OPEN_RESULT) {
if (resultCode == RESULT_OK) {
Bundle bundle = data.getExtras();
Bitmap bitmap = (Bitmap) bundle.get("data");
imageView.setImageBitmap(bitmap);
}
} else if (requestCode == PICK_RESULT) {
// 表示选择图片库的图片结果
if (resultCode == RESULT_OK) {
Uri uri = data.getData();
imageView.setImageURI(uri);
}
} else if (requestCode == OPEN_RESULT2) {
if (resultCode == RESULT_OK) {
Log.e("takePhoto", filePath);
Bitmap bitmap = BitmapFactory.decodeFile(filePath);
// imageView.setImageURI(Uri.fromFile(new File(filePath)));
imageView.setImageBitmap(bitmap);
}
}
}
/**
* 获得照片路径
*
* @return
*/
private String getPhotoPath() {
return Environment.getExternalStorageDirectory() + "/DCIM/";
}
}