Implementation method of saving multiple pictures to local in Android
- 2021-11-10 10:42:16
- OfStack
01. Problems encountered in actually developing and saving pictures
Business requirements
In the 9-grid material of the material list page, show the pictures loaded by the network request. If the user clicks the Save button, several pictures are saved locally. To do this, use glide to load the picture, then set listener to listen, and save the picture resource resource to the collection after the picture request is successful onResourceReady. At this point, if you click Save Control, the collection of picture resources will be iterated over and saved to the local folder.
Specific practice code display
At this time, the picture of the requesting network is directly converted into bitmap, and then stored in the collection. Then when you click the Save button, multiple images from the collection will be saved to the local folder.
//bitmap Picture collection
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);
// Loop through the collection of picture resources, and then start saving pictures to local folders
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 The picture quality is full
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();
}
}
// Refresh album
if (isScanner) {
scanner(context, savePath);
}
}
Problems encountered
After saving the picture locally, it is found that the picture is not the original picture, but the cropped picture displayed on the view control, that is, the size picture of ImageView.
Why do you encounter such a problem
If you pass an ImageView as an argument to. into (), Glide will use the size of ImageView to limit the size of the picture. For example, if the picture to be loaded is 1000x1000 pixels, but the size of ImageView is only 250x250 pixels, Glide will reduce the picture to a small size to save processing time and memory.
After setting the into control, that is to say, the image resource resource returned in the onResourceReady method is not the original image you loaded, but the image with the size set by ImageView. So after saving, you will find that the picture has become smaller.
So how to solve the problem?
The first method: 9 grid picture control will load network resources when showing, and then after loading the picture successfully, save the resources to the collection, and click Save to store the resources in the collection cyclically. This approach will only request 1 network. Because of the beginning
The second method: When the 9-grid picture control is displayed, the network resources will be loaded. When clicking Save 9-grid pictures, the network picture resources will be requested in turn and then the pictures will be saved locally. This method will request the network twice.
02. Request pictures directly with http and save local
http Request Picture
/**
* Request Network Picture
* @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(" Millisecond value "+time);
// Save
}
return is;
}
```
Save to Local
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. Download pictures with glide and save them locally
glide Download Picture
File file = Glide.with(ReflexActivity.this)
.load(url.get(0))
.downloadOnly(500, 500)
.get();
Save to Local
String localImgSavePath = FileSaveUtils.getLocalImgSavePath();
File imageFile = new File(localImgSavePath);
if (!imageFile.exists()) {
imageFile.getParentFile().mkdirs();
imageFile.createNewFile();
}
copy(file,imageFile);
/**
*
* @param source Input file
* @param target Output file
*/
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. How to save multiple pictures continuously
Idea: Loop subthreads
Feasible (not recommended), if I want to download 9 pictures, add sub-threads to the for loop and finally render them. There are serious defects, thread delay, and picture order cannot be guaranteed. If it is a threaded thread, the first subthread is finished, and the subthread nested in the or loop of the subthread f is not finished, so the main thread cannot get the pictures obtained in the subthread. There is also how to judge that all threads are finished, for example, after all pictures are downloaded, toast is downloaded.An unrecommended scheme
Create a thread pool to manage threads. About the thread pool encapsulation library, you can see the simple encapsulation of thread pool
This scheme does not know whether all the requested pictures in all threads are completed, and there is no guarantee of order.
ArrayList<String> images = new ArrayList<>();
for (String image : images){
// Use this thread pool, in time run Method does not crash
PoolThread executor = BaseApplication.getApplication().getExecutor();
executor.setName("getImage");
executor.execute(new Runnable() {
@Override
public void run() {
// Request network pictures and save them to local operation
}
});
}
Recommended solutions
ArrayList<String> images = new ArrayList<>();
ApiService apiService = RetrofitService.getInstance().getApiService();
// Note: Here is to save multiple pictures, and asynchronous threads can be used
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 Adj. merge Will all the observable Synthesis 1 A Observable , all of them observable Simultaneous transmission of data
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");
// Number of successful downloads And Number of picture collections 1 To, it means that all downloads were successful
if (images.size() == count.get()) {
ToastUtils.showRoundRectToast(" Save successfully ");
} else {
if (count.get() == 0) {
ToastUtils.showRoundRectToast(" Save failed ");
} else {
ToastUtils.showRoundRectToast(" Due to network problems Save successfully " + count + ", Save failed " + (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();
}
// Refresh album code omitted …
}
}
Link address: https://github.com/yangchong2...
Summarize