Can be cached.
Create a class which thread to work with the cache. I had something in the old project:
public static class FileHelper{ private static final String IMAGE_STORAGE = "images"; private static enum StorageType {INTERNAL, EXTERNAL}; private static StorageType preferStorage = StorageType.EXTERNAL; private static final Map<String, Bitmap> cache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>()); private final static int MAX_CACHED = 50; /** * Number of bytes in one KB = 2<sup>10</sup> */ private final static long SIZE_KB = 1024L; /** * Number of bytes in one MB = 2<sup>20</sup> */ public final static long SIZE_MB = SIZE_KB * SIZE_KB; private static final long NEEDED_PLACE = 2; /** * Доступна ли внешняя память для записи * @return */ public static boolean isExternalStorageWritable() { String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { return true; } return false; } /** * Доступна ли внешняя память для чтения * @return */ public static boolean isExternalStorageReadable() { String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { return true; } return false; } private static boolean hasExternalAvailableSpace(Context c) { StatFs stat = new StatFs(c.getExternalFilesDir(Environment.DIRECTORY_PICTURES).getPath()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { long sdAvailSize = (long) stat.getAvailableBlocksLong() * (long) stat.getBlockSizeLong(); sdAvailSize = (long)(sdAvailSize*1.F/ SIZE_MB); return sdAvailSize > NEEDED_PLACE; } else { @SuppressWarnings("deprecation") double sdAvailSize = (double) stat.getAvailableBlocks() * (double) stat.getBlockSize(); sdAvailSize/=SIZE_MB; return sdAvailSize > NEEDED_PLACE; } } public static String getImagePath(Context c, String id){ String dir; // чекаем во внешней памяти dir = getExtImageStorageDir(c).getAbsolutePath(); File file = new File(dir+"/"+id+".png"); // если есть, берём её if(file.exists() ) return file.getAbsolutePath() ; // иначе чекаем во внутренней памяти dir = getIntImageStorageDir(c).getAbsolutePath(); file = new File(dir+"/"+id+".png"); // возвращаем if (file.exists()) return file.getAbsolutePath(); else throw new NoSuchElementException(file.getAbsolutePath()); } public static Bitmap getImage(Context c, String id){ synchronized (cache) { // если ещё нет в кеше битмапа с этим изображением if (!cache.containsKey("img"+id)) { try { Bitmap img = null; String imgPath; imgPath = getImagePath(c, id); // тогда декодим из файла img = BitmapFactory.decodeFile(imgPath); // добавляем в кэш cache.put("img"+id, img); return img; } catch (Exception e) { e.printStackTrace(); } } return cache.get("img"+id); } } public static boolean WriteImage(Context c, Bitmap img, String id) { File dir = getImagePreferStorageDir(c); String filename = dir.getAbsolutePath() +"/"+id+".png"; FileOutputStream outputStream; for(File f :dir.listFiles()) if(f.getName().substring(0, f.getName().indexOf(".png")).equals(id)) return true; try { cache.put("img"+id, img); outputStream = new FileOutputStream(filename); ByteArrayOutputStream stream = new ByteArrayOutputStream(); img.compress(Bitmap.CompressFormat.PNG, 100, stream); byte[] byteArray = stream.toByteArray(); outputStream.write(byteArray); outputStream.close(); return true; } catch (Exception e) { e.printStackTrace(); return false; } } public static File getImagePreferStorageDir(Context c) { if(preferStorage == StorageType.EXTERNAL && isExternalStorageWritable() && hasExternalAvailableSpace(c)) return getExtImageStorageDir(c); else return getIntImageStorageDir(c); } public static File getExtImageStorageDir(Context c) { File file = new File(c.getExternalFilesDir(Environment.DIRECTORY_PICTURES), IMAGE_STORAGE); if(file.exists()); else if (!file.mkdirs()); return file; } public static File getIntImageStorageDir(Context c) { File file = new File(c.getFilesDir(), IMAGE_STORAGE); if(file.exists()) ; else if (!file.mkdirs()); return file; } private static void deleteFolder(File file){ if (file.exists()){ for(File f:file.listFiles()) f.delete(); file.delete(); } } public static void clearCache(){ LOG.d("clear cache"); cache.clear(); } public static void clear(Context c){ deleteFolder(getIntImageStorageDir(c)); deleteFolder(getExtImageStorageDir(c)); clearCache(); } }
I added a little comment there to make it clearer.
The logic is as follows:
- Check
FileHelper.getImagePath . If there is no file, there will be an exception. Then download the image from the network. - Download the image.
- Save
FileHelper.WriteImage . The image and the disk will be saved, and in memory in the cache will be. You can change the logic, remove the entire cache in memory, always load from disk. Depending on the choice, it will be saved either in external or in internal memory. - If in 1 paragraph there was no exception, then get it
FileHelper.getImage .
It can all simplify. Set explicitly so that only external memory is used, at times the code will be less. Can in memory cache remove. I just show the direction)