内存优化--减少字库缓存

优秀博客

Typeface-为自定义字体提供字体内存缓存:https://www.cnblogs.com/yongdaimi/p/8032537.html
Android 系统字体:https://blog.csdn.net/rjdeng/article/details/48545313
浅析Android字体加载原理:https://blog.csdn.net/a282255307/article/details/76870441

字库使用

1.字库组成

字库配置在framework/base/data/fonts/fonts.xml中

<familyset version="22">
    <!-- first font is default -->
    <family name="sans-serif">
        <font weight="100" style="normal">Roboto-Thin.ttf</font>
        <font weight="100" style="italic">Roboto-ThinItalic.ttf</font>
        <font weight="300" style="normal">Roboto-Light.ttf</font>
        <font weight="300" style="italic">Roboto-LightItalic.ttf</font>
        <font weight="400" style="normal">Roboto-Regular.ttf</font>
        <font weight="400" style="italic">Roboto-Italic.ttf</font>
        <font weight="500" style="normal">Roboto-Medium.ttf</font>
        <font weight="500" style="italic">Roboto-MediumItalic.ttf</font>
        <font weight="900" style="normal">Roboto-Black.ttf</font>
        <font weight="900" style="italic">Roboto-BlackItalic.ttf</font>
        <font weight="700" style="normal">Roboto-Bold.ttf</font>
        <font weight="700" style="italic">Roboto-BoldItalic.ttf</font>
    </family>

    <!-- Note that aliases must come after the fonts they reference. -->
    <alias name="sans-serif-thin" to="sans-serif" weight="100" />
    <alias name="sans-serif-light" to="sans-serif" weight="300" />
    <alias name="sans-serif-medium" to="sans-serif" weight="500" />
    ...
    <!-- fallback fonts -->
    <family lang="und-Arab" variant="elegant">
        <font weight="400" style="normal">NotoNaskhArabic-Regular.ttf</font>
        <font weight="700" style="normal">NotoNaskhArabic-Bold.ttf</font>
    </family>
    <family lang="und-Arab" variant="compact">
        <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font>
        <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
    </family>
    <family lang="und-Ethi">
        <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font>
    </family>
    <family lang="und-Hebr">
        <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
    </family>
    <family lang="und-Thai" variant="elegant">
        <font weight="400" style="normal">NotoSansThai-Regular.ttf</font>
        <font weight="700" style="normal">NotoSansThai-Bold.ttf</font>
    </family>
    ...
    </familyset>

基本字库和国家相关字库。国家相关字库在font.xml中的fallback fonts下配置

2.字库功能查询

fallback fonts之上的字库属于基本字库,基本是希腊问、拉丁文等通用文字字库
查询方法一
具体功能可以在字客网: https://www.fontke.com/font/86795/download/ ,使用字库名称查询
在这里插入图片描述
字库信息
在这里插入图片描述
查询方法二
针对fallback fonts下的字库,有一个简单的方式,如

<family lang="und-Cher">
        <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
</family>

观察多个字库命名方式,可以确定Cherokee是该字库提供的预言。有道查询Cherokee
在这里插入图片描述
字客网查询
在这里插入图片描述
对于有些缩写的,字典查不到,就在字客网上查询即可。

3. 系统字库使用

由于字库使用频繁且字库可能比较大,开机时字库需要缓存到系统。参考《浅析Android字体加载原理》博文。缓存字库的代码如下,代码以android7.1.1为例:
frameworks\base\graphics\java\android\graphics\Typeface.java

private static void init() {
        // Load font config and initialize Minikin state
        File systemFontConfigLocation = getSystemFontConfigLocation();
        File configFilename = new File(systemFontConfigLocation, FONTS_CONFIG);
        try {
            FileInputStream fontsIn = new FileInputStream(configFilename);
            FontListParser.Config fontConfig = FontListParser.parse(fontsIn);

            Map<String, ByteBuffer> bufferForPath = new HashMap<String, ByteBuffer>();

            List<FontFamily> familyList = new ArrayList<FontFamily>();
            // Note that the default typeface is always present in the fallback list;
            // this is an enhancement from pre-Minikin behavior.
            for (int i = 0; i < fontConfig.families.size(); i++) {
                FontListParser.Family f = fontConfig.families.get(i);
                if (i == 0 || f.name == null) {
                    familyList.add(makeFamilyFromParsed(f, bufferForPath));
                }
            }
            sFallbackFonts = familyList.toArray(new FontFamily[familyList.size()]);
            setDefault(Typeface.createFromFamilies(sFallbackFonts));

            Map<String, Typeface> systemFonts = new HashMap<String, Typeface>();
            for (int i = 0; i < fontConfig.families.size(); i++) {
                Typeface typeface;
                FontListParser.Family f = fontConfig.families.get(i);
                if (f.name != null) {
                    if (i == 0) {
                        // The first entry is the default typeface; no sense in
                        // duplicating the corresponding FontFamily.
                        typeface = sDefaultTypeface;
                    } else {
                        FontFamily fontFamily = makeFamilyFromParsed(f, bufferForPath);
                        FontFamily[] families = { fontFamily };
                        // 除了第一个字库,其他字库都会有自己的缓存对象
                        typeface = Typeface.createFromFamiliesWithDefault(families);
                    }
                    systemFonts.put(f.name, typeface);
                }
            }
            for (FontListParser.Alias alias : fontConfig.aliases) {
                Typeface base = systemFonts.get(alias.toName);
                Typeface newFace = base;
                int weight = alias.weight;
                if (weight != 400) {
                    newFace = new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
                }
                systemFonts.put(alias.name, newFace);
            }
            sSystemFontMap = systemFonts;

        } catch (RuntimeException e) {
            Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e);
            // TODO: normal in non-Minikin case, remove or make error when Minikin-only
        } catch (FileNotFoundException e) {
            Log.e(TAG, "Error opening " + configFilename, e);
        } catch (IOException e) {
            Log.e(TAG, "Error reading " + configFilename, e);
        } catch (XmlPullParserException e) {
            Log.e(TAG, "XML parse exception for " + configFilename, e);
        }
    }

    static {
        // 解析fonts.xml
        init();
        // Set up defaults and typefaces exposed in public API
        // 缓存不同的字库,以下部分为基础字库
        DEFAULT         = create((String) null, 0);
        DEFAULT_BOLD    = create((String) null, Typeface.BOLD);
        SANS_SERIF      = create("sans-serif", 0);
        SERIF           = create("serif", 0);
        MONOSPACE       = create("monospace", 0);

        sDefaults = new Typeface[] {
            DEFAULT,
            DEFAULT_BOLD,
            create((String) null, Typeface.ITALIC),
            create((String) null, Typeface.BOLD_ITALIC),
        };

    }

    private static File getSystemFontConfigLocation() {
    	// 字库配置文件fonts.xml放置位置
        return new File("/system/etc/");
    }

删减不必要的缓存字库

删除字库文件

在Android7.1.1上,完整的字库缓存,至少需要57M;实测删减不需要的字库后,可以省出20M内存(主要是中文字库太大,17M,其他基本是KB)。
明白了字库功能和字库使用方式,删减缓存字库简单多了吧

删减字库策略

  • 明确字库功能
  • 在字库配置文件中删掉不需要字库的配置
  • 运行软件,通过log查看,那些字库加载不到,然后修改fonts.xml。log如下
02-19 19:18:54.185  1640  1640 E Typeface: Error mapping font file /system/fonts/NotoSansNKo-Regular.ttf
02-19 19:18:54.186  1640  1640 E Typeface: Error mapping font file /system/fonts/NotoSansOlChiki-Regular.ttf
02-19 19:18:54.187  1640  1640 E Typeface: Error mapping font file /system/fonts/NotoSansRejang-Regular.ttf
02-19 19:18:54.187  1640  1640 E Typeface: Error mapping font file /system/fonts/NotoSansSaurashtra-Regular.ttf
02-19 19:18:54.188  1640  1640 E Typeface: Error mapping font file /system/fonts/NotoSansSundanese-Regular.ttf
02-19 19:18:54.188  1640  1640 E Typeface: Error mapping font file /system/fonts/NotoSansSylotiNagri-Regular.ttf
02-19 19:18:54.189  1640  1640 E Typeface: Error mapping font file /system/fonts/NotoSansSyriacEstrangela-Regular.ttf
02-19 19:18:54.190  1640  1640 E Typeface: Error mapping font file /system/fonts/NotoSansTagbanwa-Regular.ttf
02-19 19:18:54.190  1640  1640 E Typeface: Error mapping font file /system/fonts/NotoSansTaiTham-Regular.ttf
02-19 19:18:54.191  1640  1640 E Typeface: Error mapping font file /system/fonts/NotoSansTaiViet-Regular.ttf
02-19 19:18:54.191  1640  1640 E Typeface: Error mapping font file /system/fonts/NotoSansTibetan-Regular.ttf
02-19 19:18:54.192  1640  1640 E Typeface: Error mapping font file /system/fonts/NotoSansTibetan-Bold.ttf
02-19 19:18:54.192  1640  1640 E Typeface: Error mapping font file /system/fonts/NotoSansTifinagh-Regular.ttf
02-19 19:18:54.193  1640  1640 E Typeface: Error mapping font file /system/fonts/NotoSansVai-Regular.ttf
02-19 19:18:54.220  1640  1640 E Typeface: Error mapping font file /system/fonts/DroidSansFallback.ttf

如果仅仅是节省内存,到这里就结束了。如果还需要把不需要的字库从ROM中删掉,需要修改编译文件

  • 确定要删除的字库文件名
  • 从编译配置文件中删除对应的字库名

另外一种删除不需要的文件,需要根据Android编译规则,自行定义一个规则。我这里有一个,不在这里添加了,在另一篇文章说明(目前还未写,编译配置的核武器啊!)。

配置系统支持的字库

删除字库,需要配合配置系统支持的字库,否则开机系统初始化时,依然会去加载已删除的字库,会报一些错误(无影响),虽然无影响,但是秉承一个优良程序的实现,应该消除这些错误。
配置系统支持的字体,在设备目录下(如device/google)添加编译说明:

# 支持简体中文及英文,第一语言时系统默认语言
PRODUCT_LOCALES := zh-rCN en-rGB
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值