Search code examples
androidmemory-leaksruntimeexceptionandroid-fontsinflate-exception

RuntimeException: native typeface cannot be made or memory leak for custom TextView loading font


There's a HUGE problem in my code wherein I am loading a font in my assets\fonts\ folder from a custom TextView class. The first problem is that it crashes on 4.0 devices with the exception Caused by: java.lang.RuntimeException: native typeface cannot be made. I was using the same process here with the method:

public class MyTextView extends TextView {

      public MyTextView(Context context, AttributeSet attrs, int defStyle) {
          super(context, attrs, defStyle);
      }

     public MyTextView(Context context, AttributeSet attrs) {
          super(context, attrs);
      }

     public MyTextView(Context context) {
          super(context);
     }


    public void setTypeface(Typeface tf, int style) {
        if (style == Typeface.BOLD) {
            super.setTypeface(Typeface.createFromAsset(
                    getContext().getAssets(), "fonts/hirakakupronbold.ttf"));
        } else if (style == Typeface.ITALIC) {
            super.setTypeface(Typeface.createFromAsset(
                    getContext().getAssets(), "fonts/hirakakupronitalic.ttf"));
        } else {
            super.setTypeface(Typeface.createFromAsset(
                    getContext().getAssets(), "fonts/hirakakupron.ttf"));
        }
    }
}

Notice that I'm using the extension .ttf, and I found that this is causing the RunTimeException. So I converted the respective fonts with a .otf extensions, and now it runs already in 4.0 devices but has memory leaks basing here. There are workarounds here but I don't know how to use/call it. Any help would do, thank you.


Solution

  • Okay, so I finally figured that instantiating a TypeFace object inside a TextView class would cause so much load each time that same TextView is instantiated. This caused my app to lag and resulted to OutOfMemoryException eventually. So what I did was to create a different custom TypeFace class that would call my fonts from the assets so that it instantiates from the TypeFace class and not from the TextView class.

    Here's my TypeFaces class:

    public class TypeFaces {
    
        private static final Hashtable<String, Typeface> cache = new Hashtable<String, Typeface>();
    
        public static Typeface getTypeFace(Context context, String assetPath) {
            synchronized (cache) {
                if (!cache.containsKey(assetPath)) {
                    try {
                        Typeface typeFace = Typeface.createFromAsset(
                                context.getAssets(), assetPath);
                        cache.put(assetPath, typeFace);
                    } catch (Exception e) {
                        Log.e("TypeFaces", "Typeface not loaded.");
                        return null;
                    }
                }
                return cache.get(assetPath);
            }
        }
    }
    

    And the custom TextView class:

    public class TextViewHirakaku extends TextView {
    
        public TextViewHirakaku(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        public TextViewHirakaku(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public TextViewHirakaku(Context context) {
            super(context);
        }
    
        public void setTypeface(Typeface tf, int style) {
            if (style == Typeface.BOLD) {
                super.setTypeface(TypeFaces.getTypeFace(getContext(),
                        "fonts/hirakakupronbold.ttf"));
            } else if (style == Typeface.ITALIC) {
                super.setTypeface(TypeFaces.getTypeFace(getContext(),
                        "fonts/hirakakupronitalic.ttf"));
            } else {
                super.setTypeface(TypeFaces.getTypeFace(getContext(),
                        "fonts/hirakakupron.ttf"));
            }
        }
    }
    

    Notice that I'm now calling getTypeFace method from TypeFaces class here.