在Android Q中如何修复“java.lang.IllegalArgumentException: 字体已添加”错误?

18

我需要尝试安卓Q的新功能(Android Q和AppCompat v1.1.0默认关闭连字符),并且我也阅读了文档。当我按照安卓博客中的指示操作时,一切正常,但当我尝试按照文档进行操作时,遇到了错误。

我只使用了一个字体族。以下是正在运行的代码:

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()

但是当我尝试添加多个字体族时,我遇到了错误。

  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();

上述代码在文档https://developer.android.com/reference/kotlin/android/graphics/Typeface.CustomFallbackBuilder.html中给出。
那么,您能否帮我解决这个错误?

请发布完整的错误日志。 - Sergey Emeliyanov
java.lang.IllegalArgumentException: 字体 {路径=null,样式=字体样式{重量=400,倾斜=0},ttcIndex=0,轴=,语言环境列表=,缓冲区=java.nio.DirectByteBuffer[pos=0 lim=656568 cap=656568]} 已经被添加 在android.graphics.fonts.FontFamily$Builder.addFont(FontFamily.java:100) - Hinal Halvadia
3个回答

30

当您尝试将多个具有相同样式和粗细的字体注册到同一字体族时,此错误会在使用Androidx.core(或core-ktx)版本1.2.0及更高版本的Android 10中出现。

尽管您的示例是通过编程方式创建字体族,但大多数开发人员在使用字体XML时都会遇到此错误,因此让我们从那里开始。

在字体XML中,我们不能有超过一个具有相同fontStylefontWeight属性的font元素。例如,以下XML会导致此错误,因为两个font元素具有相同的样式和粗细值:

<?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>
尽管font的值不同(@font/gibson_regular@font/gibson_bold),但fontStylefontWeight相同,因此导致错误。另外,请注意,如果您未提供fontStylefontWeight属性,则它们默认为normal400,因此下一个示例也会失败:
<?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>

为解决该问题,请确保每个font元素的fontStylefontWeight组合是唯一的。例如,如果我们正确设置了gibson_bold字体的fontWeight,就可以避免错误:

<?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>

现在,当您以上的方式进行程序构建时,相同的规则适用。看起来您所参考的 API 文档没有更新以匹配源代码实际执行的内容。这是您的示例现在应该如何:

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()

在这种编程方式下,Android在通过Font.Builder加载字体时似乎可以正确地记录字体的粗细和风格,因此只要regular.ttfbold.ttf在它们的粗细和风格上有所不同,这段代码就能正常工作。

但是,如果两种字体具有相同的粗细和风格,或者如果您手动指定字体和样式相同,例如调用setWeight(400)设置粗体字体,仍然会出现此异常。

总之,在使用字体XML时,请始终为每个字体指定fontStylefontWeight。无论您是使用XML编写还是以编程方式构建它们,都要确保每个字体在字体系列中的重量和风格组合是唯一的。


谢谢您,@Dave Leeds。非常清晰地解答了问题。 - Bijon Desai
好的答案。我必须使用两种字体来支持API 25及以下版本。更改字体的重量对我有用。 - masoud jafari
我欠您一个清醒的头脑,先生。 - Dariush Malek
这可能刚刚为我节省了一到三个小时的调试时间。 - Jorn Rigter

10

注意事项:我的情况可能与你的不同,但错误是相同的。我只想帮助那些遇到这个问题的人,因为这是唯一提到该错误的问题。也许对楼主有所帮助。

事实证明,罪魁祸首是我的字体族xml文件。尽管我的文件在Android 9及以下版本中完美运行,但在Android 10(Q)上失败了。原因是我将多个fontStyles定义为“normal”:

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto">

    <font
        app:fontStyle="normal"
        app:font="@font/dosis_regular"/>

    <font
        app:fontStyle="normal"
        app:font="@font/dosis_bold"/>

    <font
        app:fontStyle="normal"
        app:font="@font/dosis_light"/>

</font-family>

当我将它们中的一个改为“正常”时,它就正常工作了。

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto">

    <font
        app:fontStyle="normal"
        app:font="@font/dosis_regular"/>

    <font
        app:fontWeight="700"
        app:font="@font/dosis_bold"/>

    <font
        app:fontStyle="italic"
        app:font="@font/dosis_light"/>

</font-family>

这个问题只在我们的一个模块中添加了 androidx.core:core-ktx:1.2.0 依赖后,在 Android 10 上才开始出现。删除此依赖项或使用您提供的解决方案都可以解决崩溃问题。 - Abhishek Bansal

0

1) 点击应用程序作为根文件夹,在其上右键单击,然后选择:新建 -> 文件夹 -> 创建资产文件夹,您将获得一个对话框:为资产创建源根

2) 将.ttf文件包含在您的资产文件夹中

enter image description here

3) 在您的活动或片段中使用如下

TextView name = (TextView) findViewById(R.id.tv_date);
    Typeface pick_text = Typeface.createFromAsset(itemView.getContext().getAssets(),  "fonts/OpenSans-Semibold.ttf");
    name.setTypeface(pick_text);

    TextView desc = (TextView) findViewById(R.id.tv_orderid);
    Typeface desc_text = Typeface.createFromAsset(itemView.getContext().getAssets(),  "fonts/NevisBold-KGwl.ttf");
    desc.setTypeface(desc_text);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接