Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"How to fix 'java.lang.IllegalArgumentException: Font has already been added' error in Android Q?"

Tags:

android

I have to try new features in Android Q (Hyphenation is off by default in Android Q and AppCompat v1.1.0) and I have also read the document. When I follow the instructions which are in the Android blog it works fine, but when I try to follow the document I found the error.

I just use an only single font family. The code below is running:

tvTest.typeface = Typeface.CustomFallbackBuilder(
            FontFamily.Builder(
                Font.Builder(resources.assets, "aguafina_script.ttf").build()).build())
        .addCustomFallback(FontFamily.Builder(
                Font.Builder(resources.assets, "Font_Solid_900.otf").build()).build())
        .build()

But when I try to add multiple font families that time I got the error.

  Font regularFont = new Font.Builder("regular.ttf").build();
  Font boldFont = new Font.Builder("bold.ttf").build();
  FontFamily family = new FontFamily.Builder(regularFont)
      .addFont(boldFont).build();
  Typeface typeface = new Typeface.CustomFallbackBuilder(family)
      .setWeight(Font.FONT_WEIGHT_BOLD)  // Set bold style as the default style.
                                         // If the font family doesn't have bold style font,
                                         // system will select the closest font.
      .build();

Above code is given in the document https://developer.android.com/reference/kotlin/android/graphics/Typeface.CustomFallbackBuilder.html

So can you please help me to solve that error?

like image 283
Hinal Halvadia Avatar asked Jul 22 '19 11:07

Hinal Halvadia


1 Answers

This error shows up in Android 10 with androidx.core (or core-ktx) version 1.2.0 and higher when you try to register multiple fonts with the same style and weight into the same font family.

Although your example is creating the font family programmatically, most developers will run into this error when using the font XML, so let's start with that.

In the font XML, we can't have more than one font element with the same fontStyle and fontWeight attributes. For example, the following XML would cause this error, because both font elements have the same values for the style and weight:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <font
        android:font="@font/gibson_regular"
        android:fontStyle="normal"
        android:fontWeight="400" />
    <font
        android:font="@font/gibson_bold"
        android:fontStyle="normal"
        android:fontWeight="400" />
</font-family>

Even though the value of font is different (@font/gibson_regular vs @font/gibson_bold), the fontStyle and fontWeight are the same, so this causes the error.

Also, note that if you do not provide the fontStyle or fontWeight attributes, they default to normal and 400 respectively, so this next example also fails:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <font
        android:font="@font/gibson_regular"
        android:fontStyle="normal"
        android:fontWeight="400" />
    <font
        android:font="@font/gibson_bold" />
</font-family>

To fix the issue, make sure that the combination of fontStyle and fontWeight for each font element is unique. For example, if we properly set the fontWeight for the gibson_bold font, we will avoid the error:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <font
        android:font="@font/gibson_regular"
        android:fontStyle="normal"
        android:fontWeight="400" />
    <font
        android:font="@font/gibson_bold"
        android:fontStyle="normal"
        android:fontWeight="700" />
</font-family>

Now, when building this out programmatically, as you are above, the same rules apply. It looks like the API docs that you're referencing haven't been updated to match what the source code is actually doing. Here's how your example should look now:

val regularFont: Font = Font.Builder(resources.assets,"regular.ttf").build()
val boldFont: Font = Font.Builder(resources.assets, "bold.ttf").build()
val family: FontFamily = FontFamily.Builder(regularFont).addFont(boldFont).build()

val typeface: Typeface = CustomFallbackBuilder(family)
    .setStyle(FontStyle(FONT_WEIGHT_BOLD, FONT_SLANT_UPRIGHT))
    .build()

When writing it programmatically like this, it appears that Android properly notes the weight and style of the fonts when loading them in via the Font.Builder, so as long as regular.ttf and bold.ttf differ in their weight and style, this code will work fine.

But you can still get this exception if the two fonts have the same weight and style, or if you manually specify the font and style to be the same, such as if you were to call setWeight(400) on the bold font.

In summary, when using the font XML, always specify the fontStyle and fontWeight for each font. And regardless of whether you're writing things with XML or building them out programmatically, make sure that the combination of weight and style is unique for each font in a font family.

like image 64
Dave Leeds Avatar answered Oct 04 '22 09:10

Dave Leeds