拍照PhotoIntentActivity总结
项目地址:http://developer.android.com/training/camera/photobasics.html
1 低版本使用高版本的api
1.1 起因
比如在gradle配置文件里:
再看getExternalStoragePublicDirectory()方法
也就是说,这个方法在api level 8中才添加进来的,而我的app需要在最小版本4中使用,如果直接使用这个方法,那个android studio会报错,编译不过去。
纠正:这里用api level 4也不行,最后改成7,好像是
这个v7包,最小是7
1.2 TargetApi注解
以上问题可以使用TargetApi注解来解决,如下
这里还需要注意一个问题,这里的compileSdkVersion也是不能小于8的,如果小于8
这里的FROYO的值是取不到的,假如我取4,那么在Build.VERSION_CODES里,只能取到1、2、3、4这四个值
这里还需要进一步的处理
这里先判断当前的版本号的大小,来进行不同的操作
1.3 Best Practice
这个app中为了获得相册的目录,使用的抽象类,在使用的类中定义一个成员变量,根据版本号不同,使用这个抽象类的子类进行实例化。【这里用接口(Interface)是否也可以呢】
抽象类:
两个实现类:
成员变量:
使用类是根据不同的版本在onCreate中进行实例化:
2 隐式intent
调用手机的摄像头进行拍照,发送的是隐式的intent,不指定具体的activity。那么就存在这样的情况:手机上的所有app都不能处理这个intent,那么我的app就会crash。所以在发隐式intent前,必须检查是否存在能够处理这个隐式intent的app,如存在,那么可以发这个intent,如果不存在,那么就不允许发这个intent
2.1 检查方法1
直接通过resolveActivity方法来判断是否存处理在给定action的intent的activity。
下面更是指出验证的重要性:如果在使用隐式intent调用 startActivityForResult(),而且这个intent没有app能够处理,app会crash。
2.2 检查方法2
这个方法是sample里给出的,核心代码:
通过PackageManager查找是否存处理在给定action的intent的activity。
3 拍小图片(Get the Thumbnail)
3.1 发intent
这里直接发送action是MediaStore.ACTION_IMAGE_CAPTURE的intent,就会调用系统的相机app来进行拍照。
Ps.发之前要检查隐式intent,如第2部分描述。
3.2 获得返回的图片
按3.1的方法直接发送intent,这里直接从返回的Intent对象获得Bundle对象,再从Bundle对象中取“data”属性,其内容就是拍照的图片
(The Android Camera application encodes the photo in the return Intent delivered to onActivityResult() as a small Bitmap in the extras, under the key "data".)
这种方法只适合用于获取小图片
4 拍大图片(Save the Full-size Photo)
拍大图片与拍小图片的区别是,需要把拍的照片缓存到sd卡上,然后再从sd卡读取这张照片进行处理。而不是直接从”data”中取出照片。
缓存到sd卡上之后,还需要找到它,所以在Activity里声名了一个保存这个路径的成员变量
4.1 发intent
与拍小图片不同,拍大图片需要额外工作
结合图中的注释,这里可以看到整个发intent请求的过程
1) 与拍小图片一样,先声名一个拍照的intent
2) 获得一个空的临时文件
3) 把这个临时文件的绝对路径保存的activity对象的成员变量中
4) 指定把拍照的图片保存到那个临时文件中
5) 发送intent
这里面涉及到很多知识点:文件操作、Uri(contentprovider),这里不是主要的内容,不做介绍
4.2 获得返回的数据
由于这里已经把拍照得到的图片放到sd卡中缓存,所以直接从图片路径就可以获得该图片了,但是可以添加一些额外工作
4.2.1 解码图片并缩放(Decode a Scaled Image)
为了防止省内存,一般不直接解码得到整个图片,而是把图片按一定的比例进行缩放再解码。
Step 1 获得ImageView的大小
Step 2 获得Bitmap的大小
这里 bmOptions.inJustDecodeBounds = true;就是为了得到大小,而不真正得到Bitmap对象
Step 3 缩放并解码得到Bitmap图片对象
4.2.2 添加到画廊(Add the Photo to a Gallery)
5 生命周期的应用
5.1 保存bitmap再显示bitmap
这两个方法,可以保证在横竖屏切换的时候,显示的图片仍然显示,如果不加这两个方法,那么横竖屏切换的时候,imageview上会不再显示图片。
可以看到,在save的时候,把图片保存到bundle中,restore的时候,再从bundle中取出来,设置到imageview中。
5.2 super方法的调用顺序
onSaveInstanceState方法的默认实现解释如下
简而言之,这个方法会默认把界面上的view保存起来,如果在override这个方法时,不调用super方法,就需要手动保存这些view。
所以5.1中看到的方法中,需要先手动把成员变量mImageBitmap保存起来,再调用super的方法
onRestoreInstanceState方法的默认实现解释如下
默认就是把onSaveInstanceState方法保存的view的状态还原回来
所以,这里在重写onSaveInstanceState和onRestoreInstanceState时,在onSaveInstanceState中是最后执行super方法,在onRestoreInstanceState是最先执行super方法。