700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Android从相册中选取图片上传到阿里云OSS

Android从相册中选取图片上传到阿里云OSS

时间:2023-01-05 19:06:58

相关推荐

Android从相册中选取图片上传到阿里云OSS

在开发APP软件中,boss突然提出想在软件中添加一个多张照片上传的功能,作为菜鸟的我,琢磨了两天,才弄出来,今天特地贴出来。本篇博客主要介绍的是将本地图片上传到服务器的方法技巧。主要技术点是:

一、运用第三方可以从相册中选取多张图片。

二、将图片进行压缩处理。

三、上传到阿里云OSS。

技术相对简单,主要是将这些技术结合起来的例子并不多,而且阿里云OSS的资料也不是很丰富,开发文档也是很简略,因此趁此机会将我的思路共享出来。

PS:请先配置好应用权限。另外,这是公司项目的一个功能,有些地方只好删除,可能看着不是很完整,有时间我再自己做个Demo共享一下。

一、图片选择

android机型几乎每个品牌都有自己的相册,因此为了兼容性,自定义一个图库是比较好的办法,而且这次开发要求选取多张图片,使用自定义的开来也是最佳方案,当然为了开发的简便性,我直接使用的第三方,如果需要自定义的,可以参考下鸿洋大神的博客。

Android 超高仿微信图片选择器 图片该这么加载

不过目前,支持多图选择的第三方控件也是挺多的,比如MultiImageSelector、MultipleImagePick、PhotoPicker、GalleryPick等等,我大致看了下,使用方法是大同小异的。这次开发中,我们使用的是GalleryPick,基本使用方法可以看看github的介绍。GalleryPick地址

这里几乎就没什么好介绍了,需要的注意的地方,YangcyYe也介绍的很详细。代码:

ImageConfig imageConfig= new ImageConfig.Builder(// GlideLoader 可用自己用的缓存库new GlideLoader())// 如果在 4.4 以上,则修改状态栏颜色 (默认黑色).steepToolBarColor(getResources().getColor(R.color.blue))// 标题的背景颜色 (默认黑色).titleBgColor(getResources().getColor(R.color.blue))// 提交按钮字体的颜色 (默认白色).titleSubmitTextColor(getResources().getColor(R.color.white))// 标题颜色 (默认白色).titleTextColor(getResources().getColor(R.color.white))// 开启多选 (默认为多选) (单选 为 singleSelect).mutiSelect().crop()// 开启拍照功能 (默认关闭).showCamera()// 多选时的最大数量 (默认 9 张).mutiSelectMaxSize(6)// 已选择的图片路径.pathList(path)// 拍照后存放的图片路径(默认 /temp/picture).filePath("/ImageSelector/Pictures").requestCode(REQUEST_CODE).build();ImageSelector.open(OrderDetailActivity.this, imageConfig); // 开启图片选择器

图片选择后是在onActivityResult函数的回调的,和自带的图库是一样的。

二、图片压缩

我们公司的项目主要是上传手机拍的照片,现在的手机像素都是极高的,一不小心就是OOM,更重要的是在天朝流量是“奢侈品”,让用户一不小心就是十几M的流量没了,这也是不行的,所以上传前必须对照片进行压缩优化。

网上相关介绍也是颇多,我直接贴代码,各位看看,应该是挺好理解的。

public class BitmapUtils {//压缩图片尺寸public static Bitmap compressBySize(String pathName, int targetWidth,int targetHeight) {BitmapFactory.Options options = new BitmapFactory.Options();opts.inJustDecodeBounds = true;// 不去真的解析图片,只是获取图片的头部信息,包含宽高等;Bitmap bitmap = BitmapFactory.decodeFile(pathName, options);// 得到图片的宽度、高度;float imgWidth = options.outWidth;float imgHeight = options.outHeight;// 分别计算图片宽度、高度与目标宽度、高度的比例;取大于等于该比例的最小整数;int widthRatio = (int) Math.ceil(imgWidth / (float) targetWidth);int heightRatio = (int) Math.ceil(imgHeight / (float) targetHeight);options.inSampleSize = 1;// 如果尺寸接近则不压缩,否则进行比例压缩if (widthRatio > 1 || widthRatio > 1) {if (widthRatio > heightRatio) {options.inSampleSize = widthRatio;} else {options.inSampleSize = heightRatio;}}//设置好缩放比例后,加载图片进内容;options.inJustDecodeBounds = false; // 这里一定要设置falsebitmap = BitmapFactory.decodeFile(pathName, opts);return bitmap;}}

一般而言,大小保持在720P左右即可,至少我是这么设置的。压缩的图片,可以通过适配器实现QQ控件图片上传时展现的效果。代码:

GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3);recycler.setLayoutManager(gridLayoutManager);adapter = new Adapter(this, path);recycler.setAdapter(adapter);

其适配器的完整代码

public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {private Context context;private LayoutInflater mLayoutInflater;private List<String> result;private final static String TAG = "Adapter";public Adapter(Context context, List<String> result) {mLayoutInflater = LayoutInflater.from(context);this.context = context;this.result = result;}@Overridepublic ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {return new ViewHolder(mLayoutInflater.inflate(R.layout.image, null));}@Overridepublic void onBindViewHolder(ViewHolder holder, int position) {Glide.with(context).load(result.get(position)).centerCrop().into(holder.image);}@Overridepublic int getItemCount() {return result.size();}public class ViewHolder extends RecyclerView.ViewHolder {ImageView image;public ViewHolder(View itemView) {super(itemView);image = (ImageView) itemView.findViewById(R.id.image);}}}

图片如此处理就可以了,但我们公司使用的是阿里云Oss,因此,我把处理过的文件又重新保存到sd里面去了。也把代码贴出来吧:

long time = System.currentTimeMillis();String t = new SimpleDateFormat("yyyy_MM_dd").format(new Date(time));String d = new SimpleDateFormat("HH_mm").format(new Date(time));// 压缩图片保存的目录路径String filePath = MyApplication.getTruename() + "/" + t + "/" + d;// 压缩后图片保存的文件名String fileName = "photo" + "(" + number + ")" + ".jpg";File file = new File(getSDPath() + "/" + "myApp" + "/" + filePath);File dir = new File(file, fileName);//将要保存图片的路径,android推荐这种写法,将目录名和文件名分开,不然容易报错。try {//压缩图片Bitmap bitmap = pressBySize(srcPath, 1280, 768);if (!file.exists()) {file.mkdirs();}if (!dir.exists()) {try {dir.createNewFile();BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dir));press(pressFormat.JPEG, 30, bos);bos.flush();bos.close();} catch (IOException e) {e.printStackTrace();}} catch (Exception e) {e.printStackTrace();}

getSdPath就是获取SD的路径,代码如下:

public static String getSDPath() {File sdDir = null;boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);//判断sd卡是否存在if (sdCardExist) {sdDir = Environment.getExternalStorageDirectory();//获取根目录} else {getBaseContext().getCacheDir().getAbsolutePath(); // 获取内置内存卡目录}return sdDir.toString();}

这样基本就完成了图片处理的操作,现在可以开始进行上传操作了。

三、图片上传

protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (requestCode == REQUEST_CODE && resultCode == RESULT_OK && data != null) {// 处理逻辑,requestcode是自己设置和传过来的,RESULT_OK是常量path = data.getStringArrayListExtra(ImageSelectorActivity.EXTRA_RESULT);// 如果多张图片,可以采取循环上传for(String srcPath, path){Log.i("MyTag", srcPath) ; // 可以看到每张原始图片的地址// 图片处理和保存的逻辑// 图片上传的逻辑,推荐不要放在循环中,多张图片容易造成线程过多};initOss(); // 配置OSS // 第一张图片的上传OssUpload(path.get(0));}}

OSS的配置,建议只实例化一次,即不要放在循环体中。

// ACCESS_ID,ACCESS_KEY是在阿里云申请的OSSCredentialProvider credentialProvider = new OSSPlainTextAKSKCredentialProvider(ACCESS_ID, ACCESS_KEY);ClientConfiguration conf = new ClientConfiguration();conf.setConnectionTimeout(15 * 1000); // 连接超时,默认15秒conf.setSocketTimeout(15 * 1000); // socket超时,默认15秒conf.setMaxConcurrentRequest(8); // 最大并发请求数,默认5个conf.setMaxErrorRetry(2); // 失败后最大重试次数,默认2次// oss为全局变量,OSS_ENDPOINT是一个OSS区域地址oss = new OSSClient(getApplicationContext(), OSS_ENDPOINT, credentialProvider, conf);

实例化后,就要将图片上传了,这个逻辑应该在onActivityResult这个方法中执行

public void ossUpload(String strPath){// 判断图片是否全部上传// 如果已经是最后一张图片上传成功,则跳出number++;if (number == path.size()) {// 结束的处理逻辑,并退出该方法return;}// 指定数据类型,没有指定会自动根据后缀名判断ObjectMetadata objectMeta = new ObjectMetadata();objectMeta.setContentType("image/jpeg");// 构造上传请求// 这里的objectKey其实就是服务器上的路径,即目录+文件名//因为目录命名逻辑涉及公司信息,被我删去,造成不知道这个objectKey不知为何物,如下是我们公司的大致命名逻辑//String objectKey = keyPath + "/" + carArr[times] + ".jpg";PutObjectRequest put = new PutObjectRequest(BUCKET_NAME, objectKey,dir.getPath());put.setMetadata(objectMeta);try {PutObjectResult putObjectResult = oss.putObject(put);} catch (ClientException e) {e.printStackTrace();} catch (ServiceException e) {e.printStackTrace();}// 异步上传时可以设置进度回调put.setProgressCallback(new OSSProgressCallback<PutObjectRequest>() {@Overridepublic void onProgress(PutObjectRequest request, long currentSize, long totalSize) {// 在这里可以实现进度条展现功能Log.d("PutObject", "currentSize: " + currentSize + " totalSize: " + totalSize);}});OSSAsyncTask task = oss.asyncPutObject(put, new OSSCompletedCallback<PutObjectRequest, PutObjectResult>() {@Overridepublic void onSuccess(PutObjectRequest request, PutObjectResult result) {Log.d("PutObject", "UploadSuccess");Log.d("ETag", result.getETag());Log.d("RequestId", result.getRequestId());// 这里进行递归单张图片上传,在外面判断是否进行跳出if (number <= path.size() - 1) {upOss(path.get(number));}}@Overridepublic void onFailure(PutObjectRequest request, ClientException clientExcepion, ServiceException serviceException) {// 请求异常if (clientExcepion != null) {// 本地异常如网络异常等clientExcepion.printStackTrace();}if (serviceException != null) {// 服务异常Log.e("ErrorCode", serviceException.getErrorCode());Log.e("RequestId", serviceException.getRequestId());Log.e("HostId", serviceException.getHostId());Log.e("RawMessage", serviceException.getRawMessage());}ToastUtils.showShort(mContext, "图片上传失败,请重新上传");return;}});}

至此,整个多图上传的过程就完成了,作为菜鸟的我,目前想出来的就是这个笨方法,希望各位大神有更好的方法,不吝赐教!

-10-25 PS:写文章时,只是想将个人想法拿出来探讨,没想到能有这么人评论与浏览,如今看来,这篇博客还存在许多问题,我计划在本周更新本篇博客,以及将demo贴出。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。