您好,登錄后才能下訂單哦!
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(); } //刷新相冊代碼省略…… }}
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。