74

I have an app that changes the font typeface for some elements. It works well for most of the people, but maybe a 0.5% get an exception when trying to change the font. The significant part of the stack trace is this:

Caused by: java.lang.RuntimeException: native typeface cannot be made
at android.graphics.Typeface.<init>(Typeface.java:147)
at android.graphics.Typeface.createFromAsset(Typeface.java:121)

As I say, it works for most of the people, so I don't think it is a problem with the font file or my code. Any suggestions about how to solve this?

Edit: This is my code:

Typeface phoneticFont = Typeface.createFromAsset(getAssets(),
                                                 "fonts/CharisSILR.ttf");
TextView tv;
tv = ((TextView) findViewById(R.id.searchPronunciationTitle));
tv.setTypeface(phoneticFont);
user936580
  • 1,223
  • 1
  • 12
  • 19

15 Answers15

68

This bug of Android OS could be the reason of your issue:

Typeface.createFromAsset leaks asset stream

Where are also a workaround in this bugreport:

I altered HTH's workaround so that the method does not assume the font path or format. The full path of the font asset must be submitted as a parameter. I also wrapped the call to createFromAsset() in a try-catch block so that the get() method will return null if the asset is not found.

public class Typefaces {
    private static final String TAG = "Typefaces";

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

    public static Typeface get(Context c, String assetPath) {
        synchronized (cache) {
            if (!cache.containsKey(assetPath)) {
                try {
                    Typeface t = Typeface.createFromAsset(c.getAssets(),
                            assetPath);
                    cache.put(assetPath, t);
                } catch (Exception e) {
                    Log.e(TAG, "Could not get typeface '" + assetPath
                            + "' because " + e.getMessage());
                    return null;
                }
            }
            return cache.get(assetPath);
        }
    }
}
HitOdessit
  • 7,198
  • 4
  • 36
  • 59
  • 4
    Thank you. If I understand it correctly, that bug's description says that the problem is a memory leak that will provoke out of memory bugs. However, this is not what I seeing: I get the "native typeface cannot be made" message without out of memory exceptions. In addition, it looks that it always fails for the user that fail, and my application doesn't use many resources. – user936580 Oct 26 '12 at 19:21
  • 1
    @user936580 the catch block when loading the typeface will avoid the exception to explode to your user. The trade-off here is an ugly font instead of a crash. I think it pays :) – Bolhoso Dec 19 '13 at 13:44
  • 1
    @Hit How do you use/call this method? I've been trying to figure out. – Compaq LE2202x Jan 06 '14 at 03:27
  • I didn't help me to get rid of the Exception, BUT it stops leaking tons of memory if I use `Typefaces` together with [androidsvg](https://code.google.com/p/androidsvg/) library, where I load multiple fonts using the `SVGExternalFileResolver`. – Dirk Nov 01 '14 at 03:10
52

I followed some of the solutions found here, with no success. I thought it was something really obscure, as programmers often do. Then somewhere I read it could be related to the font path, gotcha:

Instead of:

Typeface phoneticFont = Typeface.createFromAsset(getAssets(),
                                             "blanch_caps.ttf");   

I changed to:

Typeface phoneticFont = Typeface.createFromAsset(getAssets(),
                                             "fonts/blanch_caps.ttf");   

And my file is in assets/fonts/blanch_caps.ttf. Not it works like a charm!

joao_dv
  • 1,163
  • 10
  • 7
  • 1
    this did work for me, thanks a lot! although a little tip: my font was called with capital letters, like "COOPBL.TTF" so I had to write it in the code also with capital letters.. maybe it helps someone :) – ylka Jun 07 '14 at 19:19
  • Also fixes it for `createFromFile` – 0101100101 May 18 '16 at 13:27
50

This error came up when the font was in the library asset folder. When I copied it into assets of the application which was using this library, the error disappeared.

It seems assets cannot be imported: Android Library assets folder doesn't get copied

And here are some other cases: Issue when using a custom font - "native typeface cannot be made"

Community
  • 1
  • 1
Lumis
  • 21,517
  • 8
  • 63
  • 67
  • Thank you, but I have the font in the application asset folder. It works in most of the occasions, but for some people it doesn't work, I don't know why. – user936580 Jan 13 '13 at 22:34
  • Good to know. I have placed try/catch around loading every custom font, if error it will default to the inbuilt android font, in case a ttf font does not work on some devices. – Lumis Jan 14 '13 at 16:37
  • I think it's because you use your application's context for `getAssets()` not library ... +1 worked for me . – Saeed.re Aug 21 '14 at 19:15
25

I was struggling with this a lot. I tried every possibility and nothing helps. In the end, to problem was somewhere else. If you are building your project with Gradle, don't forget to add these lines in build.gradle file. This solved the problem in my case.

    sourceSets {
    main {
        assets.srcDirs = ['assets']
    }
}
Michal
  • 1,008
  • 1
  • 12
  • 16
  • 1
    Thank you for the answer. I'm using Eclipse, so that is not my problem. – user936580 Aug 12 '13 at 12:15
  • 10
    if we are using Android studio and gradle - Watch this. The assets dir should be directly under main. This resolved my issue. Didn't have any problem in font name and font file. This is especially important as the font name that we were using had upper/lowercases whereas asset file name should be all lowercase. – Mr. B Apr 16 '14 at 23:12
  • 15
    Under Android Studio (0.8.1 currently), I didn't have to add the lines to `build.gradle`, but I did have to put my assets folder directly under main (eg. `src\main\assets`) – Dominic K Jun 29 '14 at 04:06
  • 1
    DMan's solution was perfect for me. I didn't need to do anything in build.gradle – CodyMace Jul 15 '14 at 14:47
  • This answer was valid at that time when Gradle Android Plugin was below 0.5 and you needed to specify res folder by yourself. Now it's not necessary of course! – Michal Aug 02 '14 at 10:26
  • Don't add this bit of cod if you're using Android Studio 8.1 and above, I removed these lines and it works ! this code is for earlier versions of Android Studio – Amin Keshavarzian Oct 13 '14 at 23:49
6

You must create assets folder inside src-->main in AndroidStudio. This way worked!

Madi
  • 1,805
  • 1
  • 15
  • 9
4

In my case, it was based on the filename of the font. For some reason it was named FontName..ttf

I don't know why the double-dots were there - I looked up the original font and they were in my windows\fonts folder as FontName..ttf. Windows apparently didn't care, but Android freaked out. I renamed the file, and it's all happy now.

Tab
  • 155
  • 9
4

For my case I have found that the assets folder located in /main/java/assets but they must be in /main/assets

TooCool
  • 10,598
  • 15
  • 60
  • 85
2

Do with lower case:

Typeface phoneticFont = Typeface.createFromAsset(getAssets(),
                                             "fonts/charissilr.ttf");

Remember to also rename the file.

Pedro HCDO
  • 21
  • 1
1

Change this one

Typeface phoneticFont = Typeface.createFromAsset(getAssets(),
                                             "fonts/CharisSILR.ttf");

to

Typeface phoneticFont = Typeface.createFromAsset(getAssets(),
                                             "CharisSILR.ttf");
Kadir altınok
  • 230
  • 2
  • 5
  • With that it doesn't work because I have it in the font directory. I've tried to put it in the root directory but it fails anyway. – user936580 Feb 14 '16 at 12:26
0

I just ran into this problem when I was using the MagicTextView by qwerjk. I tried to put the MTV class in a library and use it in my main project. Here's how I got it to work:

  1. In main project assets folder, create a subfolder called fonts
  2. Copy the ttf file into the assets/fonts folder. My filename was camelcase (e.g. ReservoirGrunge.ttf) and so caps or no caps doesn't seem to matter.
  3. In my main project I inflated the MTV view from xml. Make sure the MagicTextView points to the correct library path. For example, my MTV class library was com.library.library_magictextview.MagicTextView and so my main view's xml had to read:

        <com.library.library_magictextview.MagicTextView
        android:textSize=           "50dp"
        android:textColor=          "#ffffffff"
        android:layout_width=       "fill_parent"
        android:layout_height=      "wrap_content"
    
        android:textStyle=          "bold"
        android:padding=            "20dp"
        android:gravity=            "center"
    
        r:strokeColor=          "#FFff0000"
        r:strokeJoinStyle=      "miter"
        r:strokeWidth=          "5"
        r:typeface=         "ReservoirGrunge"
        android:text=               "BobDillon" />
    
Chris Sprague
  • 3,158
  • 33
  • 24
0

In our situation, we had employed Hit's solution with the cache. The problem we introduced was that we were testing for OTF files AND TTF files within the same try block ;) Which is obviously going to fail on the first attempt for OTF if you're looking to get a TTF, but I thought it worth posting JUST incase it slipped passed someone's notice while they might be trying the same solution.

protected static Typeface getTypeface(Context p_context, String p_fontName){
    Typeface tf = null;
    try {
        tf = Typeface.createFromAsset(p_context.getAssets(), "fonts/" + p_fontName + ".otf");
    }catch(Exception e) {}

    if( tf != null ) return tf;

    try {
        tf = Typeface.createFromAsset(p_context.getAssets(), "fonts/" + p_fontName + ".ttf");
    }catch(Exception e) {}

    return tf;
}
neoRiley
  • 465
  • 6
  • 11
0

In my case i just deleted the assets folder (that i created manually) and just created a new one using the wizard. Apparently it wasn't read as the assets folder but read as just a normal folder and so getAssets() didn't work and gave me the error.

omarwaleed
  • 571
  • 7
  • 19
0

in android studio: what have worked for me is putting the ttf file straight to the assets folder without a sub folder of fonts , it didnt work with the sub folder ( (getAssets(),"fonts/oldengl.ttf") didnt work when i had the ttf in src/main/assets/fonts). this works : src/main/assets/oldengl.ttf Typeface customfont=Typeface.createFromAsset(getAssets(),"oldengl.ttf");

Stas Krantsov
  • 26
  • 1
  • 4
0

I was ran in to this issue when i imported a module which was meant to support both eclipse style projects and android studio style project.

I got my issue resolved by removing the assets from the source set as-

defaultConfig {
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName '1.0'

        sourceSets {
            main {
                java.srcDirs = ['src']
                res.srcDirs = ['res']
                //assets.srcDirs = ['assets']//commented this out because modlue was not having this directory
                manifest.srcFile 'AndroidManifest.xml'
            }
        }
    }

Or converting the project in to android studio style can also solve the issue I guess.

Sanjeet A
  • 5,171
  • 3
  • 23
  • 40
0

In my case,

I just use the previous code.. So I forget the font file in assets folder..

But I can`t figure out for 2 hours..

Possible cases for this error,

  1. Font file missing
  2. Wrong font name or wrong font extension

for ex: fonts/roboto.ttf instead of fonts/roboto.otf

Ranjithkumar
  • 16,071
  • 12
  • 120
  • 159