Android儲存多張圖片到本地
阿新 • • 發佈:2019-06-13
目錄介紹
- 01.實際開發儲存圖片遇到的問題
- 02.直接用http請求圖片並儲存本地
- 03.用glide下載圖片儲存本地
- 04.如何實現連續儲存多張圖片
- 05.關於其他介紹
好訊息
- 部落格筆記大彙總【16年3月到至今】,包括Java基礎及深入知識點,Android技術部落格,Python學習筆記等等,還包括平時開發中遇到的bug彙總,當然也在工作之餘收集了大量的面試題,長期更新維護並且修正,持續完善……開源的檔案是markdown格式的!同時也開源了生活部落格,從12年起,積累共計N篇[近100萬字,陸續搬到網上],轉載請註明出處,謝謝!
- 連結地址:https://github.com/yangchong211/YCBlogs
- 如果覺得好,可以star一下,謝謝!當然也歡迎提出建議,萬事起於忽微,量變引起質變!
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 * @return 將url圖片轉化成bitmap物件 */ 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(); } //重新整理相簿程式碼省略…… } }
其他介紹
01.關於部落格彙總連結
02.關於我的部落格
- github:https://github.com/yangchong211
- 知乎:https://www.zhihu.com/people/yczbj/activities
- 簡書:http://www.jianshu.com/u/b7b2c6ed9284
- csdn:http://my.csdn.net/m0_37700275
- 喜馬拉雅聽書:http://www.ximalaya.com/zhubo/71989305/
- 開源中國:https://my.oschina.net/zbj1618/blog
- 泡在網上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
- 郵箱:[email protected]
- 阿里雲部落格:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
- segmentfault頭條:https://segmentfault.com/u/xiangjianyu/articles
- 掘金:https://juejin.im/user/5939433efe88c2006afa0c6e