The offline profile picture is used in the current project, and the profile picture is obtained in base64 in advance. Oom problem is encountered when loading. After a series of optimization, the problem is solved.

The first step is to let the interface personnel compress the avatar data. When looking at base64 pictures, we should not treat them as strings, but directly as pictures. If the picture data is too large, the Base64 string will directly occupy too much memory, leading to OOM.

In the second step, after obtaining base64 data, decode it into byte[] and save it in a local file, which is directly saved as a picture.

Public static String saveAvatar(String name, String base64) { if (TextUtils.isEmpty(base64)) return ""; File file = getAvatarFile(name); try { byte[] decode = Base64.decode(base64, Base64.DEFAULT); FileUtil.writeByteArrayToFile(file, decode); } catch (IOException e) { LegoLog.e(e); } return file.getabsolutePath (); }Copy the code

In normal Android development, network loading frameworks such as OKHTTP are often used. In this case, interface data and local bean attribute names often correspond one to one. In this case, the corresponding base64 data fields can be set to null, and then stored in the local database. Reduce memory footprint in data transfer.

The third step is to load the avatar. To reduce load time and memory, you can use Lruchache.

public static LruCache<String, Bitmap> cache; public void initCache() { if (cache ! = null) return; int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); int size = maxMemory / 8; cache = new LruCache<String, Bitmap>(size) { @Override protected int sizeOf(String key, Bitmap value) { return (value.getRowBytes()*value.getHeight() )/ 1024; }}; } public void addToCache(String key, Bitmap value) { if (null == getBitmapFromCache(key)) { cache.put(key, value); } } public Bitmap getBitmapFromCache(String key) { if (null ! = cache) return cache.get(key); return null; }Copy the code

Loading pictures

Bitmap bitmap = ImageUtils.getInstance().getBitmapFromCache(path); if (null == bitmap) { bitmap = MyFileUtils.getAvatarBitmap(path); if (null ! = bitmap) ImageUtils.getInstance().addToCache(path, bitmap); } if (null == bitmap) { imageView.post(() -> { imageView.setImageResource(R.mipmap.ic_avatar); }); return; } Bitmap finalBitmap = bitmap; imageView.post(new Runnable() { @Override public void run() { imageView.setImageBitmap(finalBitmap); }}); Public static bitmap getAvatarBitmap(String path) {File File = new File(path); if (! file.exists()) return null; Bitmap bitmap = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { byte[] bytes = FileUtil.readFileToByteArray(file); bitmap = BitmapUtil.byteToBitmap(bytes); } catch (IOException e) { LegoLog.e(e); } finally { try { baos.close(); } catch (IOException e) { LegoLog.e(e); } } return bitmap; }Copy the code

PS. There are two methods are implemented company framework, (writeByteArrayToFile/readFileToByteArray) is not specific.

When loading images from the list, remember to use the thread pool because it is a time-consuming operation, otherwise the thread may open too many will cause oom.

I did not do the normal bitmap compression operation (using Options compression), so I still reduce the bitmap operation and put the image compression to the server. The less the local operation of bitmap, the less chance of OOM.

In the development, I encountered a pit, that is, BASE64 was directly used as the key of lrucache. This is the mistake I made at the beginning. Base64 was not treated as a file, and the key was too large, so the file address was changed later.