我学习安卓看的是《第一行代码 Android》这本书,今天我来简单谈一下“8.3.2 调用摄像头拍照”这一小节中的代码。
这一节的代码逻辑作者没有讲的特别清晰,接下来我为大家来分析一下代码。
代码如下:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
takePhoto=(Button)findViewById(R.id.take_photo);
picture=(ImageView)findViewById(R.id.picture);
//chooseFromAlbum=(Button)findViewById(R.id.choose_from_album);
takePhoto.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
File outputImage=new File(Environment.getExternalStorageDirectory(),"tempImage.jpg");
try {
if(outputImage.exists())
{
outputImage.delete();
}
outputImage.createNewFile();
}
catch(IOException e){
e.printStackTrace();
}
imageUri=Uri.fromFile(outputImage);
Intent intent=new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO);
}
});
}
@Override
protected void onActivityResult(int requestCode,int resultCode,Intent data)
{
switch(requestCode)
{
case TAKE_PHOTO:
if(resultCode==RESULT_OK)
{
Intent intent=new Intent("com.android.camera.action.CROP");
intent.setDataAndType(imageUri, "image/*");
intent.putExtra("scale", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, CROP_PHOTO);
}
break;
case CROP_PHOTO:
if(resultCode==RESULT_OK)
{
try {
Bitmap bitmap=BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
picture.setImageBitmap(bitmap);
}
catch(FileNotFoundException e){
e.printStackTrace();
}
}
break;
default:
break;
}
从代码可以分成几块来看。
一是启动相机程序。
imageUri=Uri.fromFile(outputImage);
Intent intent=new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO);
这一节中用到了一个比较特别的方法,startActivityForResult。这个我们稍后再讲。先看一下上面的这几行代码。书中有提到的我在这里就不再赘述了,重点讲一些书上没提到的。outImage是我们定义的一个文件类的变量,首先需要把它转化为一个uri对象,这个uri对象就是我们定义的outImage文件所在的路径。然后我们定义了一个隐式intent,作为开启活动的intent来启用相机程序。然后调用putExtra函数,MediaStore.EXTRA_OUTPUT
属性可以理解为,不论这个intent是用来调用照片或是音乐等等,执行完startActivityResult后生成的东西会保存在imageUri这个路径当中。
二是裁剪图片。
书上有提到,startActivityForResult这个函数执行后,会返回到onActivityResult这个函数,所以可以在onActivityResult里写在执行完相机程序后裁剪图片的代码。case TAKE_PHOTO和case CROP_PHOTO是requestcode变量,是在执行startActivityForResult(intent,requestcode)之后传入onActivityResult函数的,用来判断此时是刚拍完相片要裁剪(case TAKE_PHOTO)还是刚裁剪完要显示在ImageView上(case CROP_PHOTO)。至于resultcode在程序中我们只看到一种值,就是RESULT_OK,那是因为我们的这个项目中就只有一个活动,当活动不止一个时,resultcode可以用于判断是哪个活动返回的数据,通过activity.RESULT_OK。讲解了这两个函数,接下来继续看代码。
Intent intent=new Intent("com.android.camera.action.CROP");
intent.setDataAndType(imageUri, "image/*");
intent.putExtra("scale", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, CROP_PHOTO);
这里的intent和刚才调用手机拍照类似,它们的action是android内置的,只要你传入这个intent,手机里的对应活动就会响应。setDataAndType函数是用来打开文件的,现在我们已经调用相机拍好了照片,接下来就要打开这个相片文件,对它进行裁剪。setDataAndType函数利用了Uri路径打开相片,第二个参数是文件的类型。然后通过putExtra(MediaStore.EXTRA_OUTPUT, imageUri)再次设置裁剪完图片后的存储位置,最后调用活动。
接下来就是裁剪图片后在页面上的显示。我还没太弄明白为什么要用Bitmap来显示,不过这个知识点不难,我就不说了。
最后补充一个小细节,相信大家也发现了我漏了一块没讲,代码如下。
if(outputImage.exists())
{
outputImage.delete();
}
outputImage.createNewFile();
这段代码理解起来也很简单。在我们调用相机拍照并且已经显示在页面上之后,如果我们还需要重新拍照来在页面上显示新的图片,应该判断此时页面上是否有图片,如果有的话将它删除并且重新创造一个文件。这是细节方面的问题,大家在写demo的时候也要尽量考虑的全面,将功能做到尽可能完善。