网上许多图片上传的实现,但笔者在开发中发现,这些并不是一个具体的流程。因此,写此文章总结下图片的上传流程。
图片上传流程,对于大部分app来说,是最长见的操作,拥有一个具体的流程,在开发中会带来许多方便。
流程具体如下:
1、选择图片(拍摄、从图片库选择)
2、压缩与本地缓存,图片需要压缩,很容易理解,为防止OOM。而缓存是保存压缩后的图片,以便上传到后台。
2、界面呈现选择的图片。
3、调用后台接口,上传图片。
4、取消上传后或者上传成功后,删除缓存。
解释:
图片呈现时,最好是先压缩再呈现。压缩方法网上很多,但笔者对于压缩方法,暂未找到一个可控制压缩后图片大小的方法,网上大部分方法为压缩后图片大小不可控。
图片压缩了,为什么还需要做缓存,原因:
图片上传有许多种方法,如字节流,Base64等。
在Android中,app与后台通信时,都有封装好的通信方法。相信许多开发者也会选择如AsyncHttpClient这样的类库,实现起来简单易用。另外,一般图片上传时,不会简单的只上传图片,图片可能是附加的信息。这时,采用字节流,Base64等方法时,会出现两个问题,一个是怎么把字段信息和图片一起上传,二是若分开上传,怎么保证字段信息和图片同步。
其实,AsyncHttpClient已经有关于这些问题的解决方法,AsyncHttpClient里,已经可以实现了上传file,利用这个就很好的解决了上述问题。
AsyncHttpClient上传图片,是以file的形式上传的,而在android中,压缩后的图片是Bitmap形式,所以需要反压缩后的图片保存起来,以File的形式再上传。
如以下代码:
String title = "title";
File file = new File(path);
RequestParams requestParams = new RequestParams();
requestParams.put("title", title);
requestParams.put("file" , file);
言归正传,以下是各个流程的具体实现。
一、选择图片
1、界面跳转选择图片
//跳转拍摄照片
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent,101);
//跳转从照片库选择
Intent intent2 = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent2,102);
2、返回结果处理
saveImageCahce(bitmap); 该方法为缓存方法,下面会写到。
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 101) {
switch (resultCode) {
case Activity.RESULT_OK:
Bundle bundle = data.getExtras();
Bitmap bitmap = (Bitmap) bundle.get("data");
//缓存
saveImageCahce(bitmap);
break;
case Activity.RESULT_CANCELED:
break;
}
} else if (requestCode == 102) {
switch (resultCode) {
case Activity.RESULT_OK:
Uri uri = data.getData();
Cursor cursor = getContentResolver().query(uri, null, null,null, null);
cursor.moveToNext();
String imgPath = cursor.getString(1);
cursor.close();
Bitmap bitmap = BitmapFactory.decodeFile(imgPath);
//缓存
saveImageCahce(bitmap);
break;
case Activity.RESULT_CANCELED:
break;
}
}
}
关于多图上传
在多图上传时,与单图上传类似,只是把单图上加上个循环步骤。
不同点是,选择图片时。不能调用Android自带的图片选择器,而需要另做图片选择。关于多图选择,网上很多,请自行搜索。
这里只需要把,多图选择后的结果的图片地址,以list形式,返回就行。
注意,返回的图片地址一定要是该图片的绝对路径。
代码如下:
@Override
protected void onActivityResult(int arg0, int arg1, Intent arg2) {
// TODO Auto-generated method stub
super.onActivityResult(arg0, arg1, arg2);
if (arg1 == 1001) {
// 获取返回结果中图片地址数据
Bundle bundle = arg2.getExtras();
List temp = new ArrayList();
temp = bundle.getStringArrayList("files");
//循环
for (int i = 0; i < temp.size(); i++) {
String file_path = temp.get(i);
//生成图片缓存地址
file_path =
//获取缓存文件夹地址
//获取文件名信息
FileManager.getSaveImagePath()
+ file_path.substring(file_path.lastIndexOf("/") + 1,
file_path.length());
//生成文件夹
FileHelper.createDirectory(FileManager.getSaveImagePath());
//压缩与保存图片
File file = new File(file_path);
try {
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream out = new FileOutputStream(file);
Util util = new Util(ReleaseRentalActivity.this);
Bitmap bitmap = util.getBitmapCompression(temp.get(i));
if (bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)) {
out.flush();
out.close();
}
mImgFiles.add(file_path);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
refreshImages();
}
}
二、压缩与本地缓存
private void saveImageCahce(Bitmap avatar) {
CacheUtils cu = new CacheUtils();
String image_path = cu.getAvatarCache(UserInfoActivity.this, avatar);
//呈现
Bitmap bitmap = BitmapFactory.decodeFile(image_path);
mUserAvatar.setImageBitmap(bitmap);
}
生成头像缓存
/**
* 生成头像缓存
*
* @param con
* @param avatar
* @return
*/
public String getAvatarCache(Context con, Bitmap avatar) {
//图片保存绝对路径
String file_path = FileManager.getSaveImagePath() + AVATAR_PATH;
//图片保存的文件夹
FileHelper.createDirectory(FileManager.getSaveImagePath());
File file = new File(file_path);
try {
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream out = new FileOutputStream(file);
ImageFactory imageFactory = new ImageFactory(con);
//压缩图片并保存
Bitmap bitmap = imageFactory.comp(avatar);
if (bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)) {
out.flush();
out.close();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//返回该图片缓存路径
return file_path;
}
三、上传图片
以RequestParams参数,进行AsyncHttpClient访问
String title = "title";
File file = new File(path);
RequestParams requestParams = new RequestParams();
requestParams.put("title", title);
requestParams.put("file" , file);
php后台参考代码
$base_path = "./upload/";
$target_path = $base_path . basename ( $_FILES ['uploadfile'] ['name'] );
if (move_uploaded_file ( $_FILES ['uploadfile'] ['tmp_name'], $target_path )) {
$array = array (
"code" => "1",
"message" => $_FILES ['uploadfile'] ['name']
);
echo json_encode ( $array );
} else {
$array = array (
"code" => "0",
"message" => "There was an error uploading the file, please try again!" . $_FILES ['uploadfile'] ['error']
);
echo json_encode ( $array );
}
?>
四、删除缓存文件
直接以文件删除方式删除