欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android保存多张图片到本地的实现方法

程序员文章站 2023-01-07 14:57:47
01.实际开发保存图片遇到的问题 业务需求 在素材list页面的九宫格素材中,展示网络请求加载的图片。如果用户点击保存按钮,则保存若干张图片到本地。具体做法是,使用...

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://img1.haowmc.com/hwmc/material/2019061079934131.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();
  }
  //刷新相册代码省略……
 }
}

链接地址:https://github.com/yangchong2...

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。