温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Android中怎么保存多张图片到本地

发布时间:2021-08-07 15:02:45 来源:亿速云 阅读:138 作者:Leah 栏目:编程语言

Android中怎么保存多张图片到本地,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

01.实际开发保存图片遇到的问题

业务需求

在素材list页面的九宫格素材中,展示网络请求加载的图片。如果用户点击保存按钮,则保存若干张图片到本地。具体做法是,使用glide加载图片,然后设置listener监听,在图片请求成功onResourceReady后,将图片资源resource保存到集合中。这个时候,如果点击保存控件,则循环遍历图片资源集合保存到本地文件夹。

具体做法代码展示

这个时候直接将请求网络的图片转化成bitmap,然后存储到集合中。然后当点击保存按钮的时候,将会保存该组集合中的多张图片到本地文件夹中。

//bitmap图片集合private ArrayList<Bitmap> bitmapArrayList = new ArrayList<>();RequestOptions requestOptions = new RequestOptions() .transform(new GlideRoundTransform(mContext, radius, cornerType));GlideApp.with(mIvImg.getContext()) .asBitmap() .load(url) .listener(new RequestListener<Bitmap>() {  @Override  public boolean onLoadFailed(@Nullable GlideException e, Object model,     Target<Bitmap> target, boolean isFirstResource) {  return true;  }  @Override  public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target,      DataSource dataSource, boolean isFirstResource) {  bitmapArrayList.add(resource);  return false;  } }) .apply(requestOptions) .placeholder(ImageUtils.getDefaultImage()) .into(mIvImg);   //循环遍历图片资源集合,然后开始保存图片到本地文件夹mBitmap = bitmapArrayList.get(i);savePath = FileSaveUtils.getLocalImgSavePath();FileOutputStream fos = null;try { File filePic = new File(savePath); if (!filePic.exists()) { filePic.getParentFile().mkdirs(); filePic.createNewFile(); } fos = new FileOutputStream(filePic); // 100 图片品质为满 mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);} catch (IOException e) { e.printStackTrace(); return null;} finally { if (fos != null) { try {  fos.flush();  fos.close(); } catch (IOException e) {  e.printStackTrace(); } } //刷新相册 if (isScanner) { scanner(context, savePath); }}

遇到的问题

保存图片到本地后,发现图片并不是原始的图片,而是展现在view控件上被裁切的图片,也就是ImageView的尺寸大小图片。

为什么会遇到这种问题

如果你传递一个ImageView作为.into()的参数,Glide会使用ImageView的大小来限制图片的大小。例如如果要加载的图片是1000x1000像素,但是ImageView的尺寸只有250x250像素,Glide会降低图片到小尺寸,以节省处理时间和内存。

在设置into控件后,也就是说,在onResourceReady方法中返回的图片资源resource,实质上不是你加载的原图片,而是ImageView设定尺寸大小的图片。所以保存之后,你会发现图片变小了。

那么如何解决问题呢?

第一种做法:九宫格图片控件展示的时候会加载网络资源,然后加载图片成功后,则将资源保存到集合中,点击保存则循环存储集合中的资源。这种做法只会请求一个网络。由于开始

第二种做法:九宫格图片控件展示的时候会加载网络资源,点击保存九宫格图片的时候,则依次循环请求网络图片资源然后保存图片到本地,这种做法会请求两次网络。

02.直接用http请求图片并保存本地

http请求图片

/** * 请求网络图片 * @param url   url */private static long time = 0;public static InputStream HttpImage(String url) { long l1 = System.currentTimeMillis(); URL myFileUrl = null; Bitmap bitmap = null; HttpURLConnection conn = null; InputStream is = null; try { myFileUrl = new URL(url); } catch (MalformedURLException e) { e.printStackTrace(); } try { conn = (HttpURLConnection) myFileUrl.openConnection(); conn.setConnectTimeout(10000); conn.setReadTimeout(5000); conn.setDoInput(true); conn.connect(); is = conn.getInputStream(); } catch (IOException e) { e.printStackTrace(); } finally { try {  if (is != null) {  is.close();  conn.disconnect();  } } catch (IOException e) {  e.printStackTrace(); } long l2 = System.currentTimeMillis(); time = (l2-l1) + time; LogUtils.e("毫秒值"+time); //保存 } return is;}```

保存到本地

InputStream inputStream = HttpImage( "https://cache.yisu.com/upload/information/20201211/272/44845.jpg");String localImgSavePath = FileSaveUtils.getLocalImgSavePath();File imageFile = new File(localImgSavePath);if (!imageFile.exists()) { imageFile.getParentFile().mkdirs(); try { imageFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); }}FileOutputStream fos = null;BufferedInputStream bis = null;try { fos = new FileOutputStream(imageFile); bis = new BufferedInputStream(inputStream); byte[] buffer = new byte[1024]; int len; while ((len = bis.read(buffer)) != -1) { fos.write(buffer, 0, len); }} catch (Exception e) { e.printStackTrace();} finally { try { if (bis != null) {  bis.close(); } if (fos != null) {  fos.close(); } } catch (IOException e) { e.printStackTrace(); }}

03.用glide下载图片保存本地

glide下载图片

File file = Glide.with(ReflexActivity.this) .load(url.get(0)) .downloadOnly(500, 500) .get();

保存到本地

String localImgSavePath = FileSaveUtils.getLocalImgSavePath();File imageFile = new File(localImgSavePath);if (!imageFile.exists()) { imageFile.getParentFile().mkdirs(); imageFile.createNewFile();}copy(file,imageFile);/** * * @param source 输入文件 * @param target 输出文件 */public static void copy(File source, File target) { FileInputStream fileInputStream = null; FileOutputStream fileOutputStream = null; try { fileInputStream = new FileInputStream(source); fileOutputStream = new FileOutputStream(target); byte[] buffer = new byte[1024]; while (fileInputStream.read(buffer) > 0) {  fileOutputStream.write(buffer); } } catch (Exception e) { e.printStackTrace(); } finally { try {  if (fileInputStream != null) {  fileInputStream.close();  }  if (fileOutputStream != null) {  fileOutputStream.close();  } } catch (IOException e) {  e.printStackTrace(); } }}```

04.如何实现连续保存多张图片

思路:循环子线程

可行(不推荐), 如果我要下载9个图片,将子线程加入for循环内,并最终呈现。  有严重缺陷,线程延时,图片顺序不能做保证。如果是线程套线程的话,第一个子线程结束了,嵌套在该子线程f的or循环内的子线程还没结束,从而主线程获取不到子线程里获取的图片。  还有就是如何判断所有线程执行完毕,比如所有图片下载完成后,吐司下载完成。

不建议的方案

创建一个线程池来管理线程,关于线程池封装库,可以看线程池简单封装

这种方案不知道所有线程中请求图片是否全部完成,且不能保证顺序。

ArrayList<String> images = new ArrayList<>();for (String image : images){ //使用该线程池,及时run方法中执行异常也不会崩溃 PoolThread executor = BaseApplication.getApplication().getExecutor(); executor.setName("getImage"); executor.execute(new Runnable() {  @Override  public void run() {   //请求网络图片并保存到本地操作  } });}

推荐解决方案

ArrayList<String> images = new ArrayList<>();ApiService apiService = RetrofitService.getInstance().getApiService();//注意:此处是保存多张图片,可以采用异步线程ArrayList<Observable<Boolean>> observables = new ArrayList<>();final AtomicInteger count = new AtomicInteger();for (String image : images){ observables.add(apiService.downloadImage(image)   .subscribeOn(Schedulers.io())   .map(new Function<ResponseBody, Boolean>() {    @Override    public Boolean apply(ResponseBody responseBody) throws Exception {     saveIo(responseBody.byteStream());     return true;    }   }));}// observable的merge 将所有的observable合成一个Observable,所有的observable同时发射数据Disposable subscribe = Observable.merge(observables).observeOn(AndroidSchedulers.mainThread())  .subscribe(new Consumer<Boolean>() {   @Override   public void accept(Boolean b) throws Exception {    if (b) {     count.addAndGet(1);     Log.e("yc", "download is succcess");    }   }  }, new Consumer<Throwable>() {   @Override   public void accept(Throwable throwable) throws Exception {    Log.e("yc", "download error");   }  }, new Action() {   @Override   public void run() throws Exception {    Log.e("yc", "download complete");    // 下载成功的数量 和 图片集合的数量一致,说明全部下载成功了    if (images.size() == count.get()) {     ToastUtils.showRoundRectToast("保存成功");    } else {     if (count.get() == 0) {      ToastUtils.showRoundRectToast("保存失败");     } else {      ToastUtils.showRoundRectToast("因网络问题 保存成功" + count + ",保存失败" + (images.size() - count.get()));     }    }   }  }, new Consumer<Disposable>() {   @Override   public void accept(Disposable disposable) throws Exception {    Log.e("yc","disposable");   }  });      private void saveIo(InputStream inputStream){ String localImgSavePath = FileSaveUtils.getLocalImgSavePath(); File imageFile = new File(localImgSavePath); if (!imageFile.exists()) {  imageFile.getParentFile().mkdirs();  try {   imageFile.createNewFile();  } catch (IOException e) {   e.printStackTrace();  } } FileOutputStream fos = null; BufferedInputStream bis = null; try {  fos = new FileOutputStream(imageFile);  bis = new BufferedInputStream(inputStream);  byte[] buffer = new byte[1024];  int len;  while ((len = bis.read(buffer)) != -1) {   fos.write(buffer, 0, len);  } } catch (Exception e) {  e.printStackTrace(); } finally {  try {   if (bis != null) {    bis.close();   }   if (fos != null) {    fos.close();   }  } catch (IOException e) {   e.printStackTrace();  }  //刷新相册代码省略…… }}

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI