1

In my starting activity, I call FontFactory.init(getApplicationContext()); to set Context to FontFactory class.

I have also class which extends TextView and in constructor of this TextView there is setTypeface(FontFactory.Fonts.ROBOTO_LIGHT.getFont());. So a font from file is loaded when first needed, not before, during startup.

Problem is that only sometimes, not every time there is a startup error and application crashes:

InflateException: Binary XML file line .. - error inflating class LayoutWithExtendedTextView

Caused by NullPointerException in Typeface nativeCreateFromAsset, createFRomAsset and FontFactory.loadFont(FontFactory.java:46)

Line 46 is return Typeface.createFromAsset(assetManager, fontEnum.getPath());

My FontFactory class:

public final class FontFactory {

    public enum Fonts {
        ROBOTO_CONDENSED("fonts/Roboto-Condensed.ttf"), ROBOTO_LIGHT(
                "fonts/Roboto-Light.ttf"), ROBOTO_MEDIUM(
                "fonts/Roboto-Medium.ttf"), ROBOTO_REGULAR(
                "fonts/Roboto-Regular.ttf");

        private String path;
        private Typeface loadedFont = null;

        private Fonts(String path) {
            this.path = path;
        }

        public String getPath() {
            return path;
        }

        public void setLoadedFont(Typeface font) {
            this.loadedFont = font;
        }

        public Typeface getFont() {
            if (loadedFont == null) {
                this.loadedFont = FontFactory.loadFont(this);
            }
            return loadedFont;
        }
    }

    private static final String TAG = "FontFactory";
    private static AssetManager assetManager;

    public static void init(Context context) {
        assetManager = context.getAssets();
    }

    private static Typeface loadFont(FontFactory.Fonts fontEnum) {
        return Typeface.createFromAsset(assetManager, fontEnum.getPath());
    }
}

Is there some delay when loading asset?

Thank you.

Xdg
  • 1,735
  • 2
  • 27
  • 42

1 Answers1

1

metrhod createFromAsset calls nativeCreateFromAsset which is native C++ code.

static JNINativeMethod gTypefaceMethods[] = {
{ "nativeCreate",        "(Ljava/lang/String;I)I", (void*)Typeface_create },
{ "nativeCreateFromTypeface", "(II)I", (void*)Typeface_createFromTypeface },
{ "nativeUnref",              "(I)V",  (void*)Typeface_unref },
{ "nativeGetStyle",           "(I)I",  (void*)Typeface_getStyle },
{ "nativeCreateFromAsset",    "(Landroid/content/res/AssetManager;Ljava/lang/String;)I",
                                       (void*)Typeface_createFromAsset },
{ "nativeCreateFromFile",     "(Ljava/lang/String;)I",
                                       (void*)Typeface_createFromFile }
};

Digging through the code, I found the following implementation of Typeface_createFromAsset.

static SkTypeface* Typeface_createFromAsset(JNIEnv* env, jobject,
                                        jobject jassetMgr,
                                        jstring jpath) {

NPE_CHECK_RETURN_ZERO(env, jassetMgr);
NPE_CHECK_RETURN_ZERO(env, jpath);

AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr);
if (NULL == mgr) {
    return NULL;
}

AutoJavaStringToUTF8    str(env, jpath);
Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
if (NULL == asset) {
    return NULL;
}

return SkTypeface::CreateFromStream(new AssetStream(asset, true));
}

This method returns null in the following two circumstances:

  • First, the asset manager provided is null
  • Second, it was unable to create load the asset from the file system.

Also, read question “Native typeface cannot be made” only for some people which provides probably the most complete information regarding the issue (not worth copy/pasting here)

Community
  • 1
  • 1
kouretinho
  • 2,190
  • 1
  • 23
  • 37