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

Compaq LE2202x picture Compaq LE2202x · Jan 6, 2014 · Viewed 10.5k times · Source

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.

Answer

Compaq LE2202x picture Compaq LE2202x · Jan 28, 2014

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.