Wednesday 1 June 2016

Solving Memory leaks issue with custom font in Android

Today I will discuss some memory leak issue while using custom fonts in android.

Using custom fonts may leads to some serious memory leak issues so while using custom fonts you should avoid this memory leaks.

Steps to reproduce 
1. Write an application that calls Typeface.createFromAsset() multiple times.
2. Make sure that the typeface objects are out of scope and the garbage collector has completed at least one pass.
3. Run adb shell dumpsys meminfo <your app package>

For complete issue discussion please visit https://code.google.com/p/android/issues/detail?id=9904

Normally we use custom fonts as below
Typeface font = Typeface.createFromAsset(getContext().getAssets(), "fonts/Arial.ttf");
tv.setTypeface(font);

Please a take a look on memory dumb, when custom views are used.

** MEMINFO in pid 10045 [com.android.test] **
                         Shared  Private     Heap     Heap     Heap
                   Pss    Dirty    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------
       Native        0        0        0    15596    14337     1258
       Dalvik    44483    11156    44292    64775    43074    21701
       Cursor        0        0        0                           
       Ashmem        0        0        0                           
    Other dev        4       36        0                           
     .so mmap     5380     2196     4752                           
    .jar mmap        0        0        0                           
    .apk mmap      362        0        0                           
    .ttf mmap      102        0        0                           
    .dex mmap      964        0        0                           
   Other mmap     1283      320      204                           
      Unknown     9452      528     9448                           
        TOTAL    62030    14236    58696    80371    57411    22959

 Objects
               Views:      981         ViewRootImpl:        2
         AppContexts:        4           Activities:        3
              Assets:       28        AssetManagers:       28
       Local Binders:       16        Proxy Binders:       19
    Death Recipients:        0
     OpenSSL Sockets:        1

 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0


 Asset Allocations
    zip:/data/app/com.android.test-2.apk:/resources.arsc: 135K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS.ttf: 133K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS.ttf: 133K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS.ttf: 133K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS.ttf: 133K
    zip:/data/app/com.android.test-2.apk:/assets/fonts/Trebuchet MS Bold.ttf: 123K
So instead of this we should cache the Typeface as below


public class FontCache {

    private static Hashtable<String, Typeface> fontCache = new Hashtable<String, Typeface>();

    public static Typeface get(String name, Context context) {
        Typeface tf = fontCache.get(name);
        if(tf == null) {
            try {
                tf = Typeface.createFromAsset(context.getAssets(), name);
            }
            catch (Exception e) {
                return null;
            }
            fontCache.put(name, tf);
        }
        return tf;
    }
}



Usage
Typeface tf = FontCache.get("fonts/MavenPro-Regular.ttf", this);
mTestTV.setTypeface(tf);
mTestTV.setText("Safe typeface use");


References
https://stackoverflow.com/questions/16901930/memory-leaks-with-custom-font-for-set-custom-font

https://stackoverflow.com/questions/23977114/custom-font-in-android-leaking-memory

Please try to use custom font with and without caching in a listview of some 100 items you will get the difference

Source code : https://github.com/gaikwadChetan93/SafeCustomFonts

Try it yourself
Please suggest if any update.
Updates are always welcome
HAPPY CODING :)

My Apps MobileUtility