在Android开发中经常会遇到需要上传图片的场景,虽然现在有很多很好的第三方框架可供使用,而且傻瓜集成,配置简单。但是有些时候总感觉第三方框架过于臃肿,用着总感觉没有自己写的来得踏实。所以让我们也任性一回,自己写一个图片上传吧。
准备工作
图片上传听起来没有多少事要做,但是小细节还是很繁杂的,更有很多藏在背后的知识。一整套下来,收获还是会很大的。那么具体会有那些步骤呢,别急,容我捋捋:
- 获得图片源(拍摄或选取)
- 编辑(获取基本信息,压缩,调整大小)
- 编码
- 上传
看吧,虽然看起来很简单的任务,认真下来,会发现有很多的知识会牵扯进来,所以废话不多说,让我们开始吧!
正式开始
获取图片源
一般我们会有两种方式来获得图片源——拍照、从系统选取。先说拍照,拍照对于国内开发者而言简直就是噩梦般的存在,由于某些厂商所谓的定制,在适配中会有各种各样莫名其妙的Bug存在,但由于篇幅有限,今天仅仅展示最常规的操作。
通常,假如需要拍照的话,我们需要在Manifest文件中声明我们需要使用相机硬件,所以需要假如特性声明
<uses-feature android:name="android.hardware.camera" />
接下来就是真正的编码工作了,一般我们有两种途径来获得拍摄结果,假如对图片的要求不是太高,我们可以选择直接获取缩略图。系统拍摄完图片后会将结果编码成一个较小的Bitmap,放在Intent对象的extra里,作为key为data的值,返回给调用者缩略图。这时候我们拿到的直接就是Bitmap对象,就可以直接进入下一步了。但这种情况一般不常见,因为缩略图的使用情况很少,一般会用来做icon。尽管简单,但是我们还是来看看怎样做吧
// 获取图片,仅仅需要缩略图
static final int TAKE_PHOTO=1;
//调用拍照
Intent intent =new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if(null != intent.resolveActivity(getPackagerManager())){
startActivityForResult(intent,TAKE_PHOTO);
}
@Override
// 拍摄结束
protected void onActivityResult(int requestCode,int resultCode,Intent data){
if(RESULT_OK==resultCode && TAKE_PHOTO==requestCode){
Bundle extras=data.getExtras();
Bitmap bitmap=(Bitmap)extras.get("data");
...
}
}
但是假如我们需要高清大图呢,为此我们付出的代价是需要码更多的代码。
高清大图需要我们在调用相机拍摄前,提供一个Uri来提供图片的保存位置,名称等信息。既然涉及到保存,那肯定少不了权限声明:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
当然,假如你不想用户拍摄的图片公开,并且应用运行在Android 4.4及以上的平台的话,你不需要这个权限,但是你只能将图片保存在getExternalFilesDir()返回的目录下。
所以通常这个权限还是需要的。
通常,我们会从File对象获得Uri,所以接下来我们需要创建File对象。这里需要注意一个小问题,为了避免文件名冲突造成不必要的问题,我们通常将File对象的名称中加入时间戳,并且放在外部存储的图片目录中。
// 生成保存图片的File对象
private File createFile() throws IOException{
//文件名
String fileName="IMAG_"+new SimpleDataFormat("yyyyMMdd_HHmmss").format(new Date());
//文件目录
File fileDir=Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
// 创建(文件名,文件扩展名,所属目录)
File target=new File(fileName,".jpg",fileDir);