Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 5.0 system_fonts.xml文件的解析過程

Android 5.0 system_fonts.xml文件的解析過程

編輯:關於Android編程

Android 5.0 system_fonts.xml文件的解析過程

首先看看看5.0 中familyset version="22" 的格式
 20     
 21         Roboto-Thin.ttf
 22         Roboto-ThinItalic.ttf
 23         Roboto-Light.ttf
 24         Roboto-LightItalic.ttf
 25         Roboto-Regular.ttf
 26         Roboto-Italic.ttf
 27         Roboto-Medium.ttf
 28         Roboto-MediumItalic.ttf
 29         Roboto-Black.ttf
 30         Roboto-BlackItalic.ttf
 31         Roboto-Bold.ttf
 32         Roboto-BoldItalic.ttf
 33     

 35     
 36     
 37     
 38     
 39     
 40     
 41     
 42     
 43     

在Typeface.java中靜態類實現了對system_fonts.xml文件的的解析過程

一. system_fonts.xml文件存在設備的/system/etc/system_fonts.xml
二. Typyface文件對system_fonts.xml文件的解析過程
需要兩個比較重要的數據結構:
Font
public static class Font {
        public String fontName;        //用於存儲Fontfile的文件所在的Path
        public int weight;             //新增加的字段,表示字體大小
        public boolean isItalic;       //是否為斜體
    }
Family
    public static class Family {
        public String name;          //對應於Family的名字, eg:sans-serif
        public List fonts;     //屬於該Family的Font集合
        public String lang;          //語言屬性
        public String variant;      
    }

再看看system_fonts.xml文件的初始化代碼:
private static void init() {
        // Load font config and initialize Minikin state
        //以下根據配置文件的絕對路徑(/system/etc/system_fonts.xml)得到File對象,就沒什麼好分析的了
        File systemFontConfigLocation = getSystemFontConfigLocation();
        File configFilename = new File(systemFontConfigLocation, FONTS_CONFIG);

        //無關代碼直接給省去了,直接分析解析代碼(剩余的代碼後頭再進行分析)
        try {
            FileInputStream fontsIn = new FileInputStream(configFilename); //打開文件,沒什麼可以分析的
            FontListParser.Config fontConfig = FontListParser.parse(fontsIn);//所有的核心都在這個parse中進行處理的
            .....

        } catch (RuntimeException e) {
        ..............
        }
    }

要想知道parse到底干了什麼,直接看源代碼

    /* Parse fallback list (no names) */
    public static Config parse(InputStream in) throws XmlPullParserException, IOException {
        try {
            XmlPullParser parser = Xml.newPullParser(); //很明顯這個是一個Xml文件解析工具類,不必要去深究了
            parser.setInput(in, null);
            parser.nextTag();
            return readFamilies(parser); //重點分析這個函數
        } finally {
            in.close();
        }
    }

parse的在利用輸入流創建了Xml解析工具後,和行工作就轉交給readFamilies這個函數了

    private static Config readFamilies(XmlPullParser parser)
            throws XmlPullParserException, IOException {
        Config config = new Config(); //配置文件的所有解析結果都是存儲於這個變量中

        parser.require(XmlPullParser.START_TAG, null, "familyset");
        while (parser.next() != XmlPullParser.END_TAG) {
            if (parser.getEventType() != XmlPullParser.START_TAG) continue;
            //以下兩個if 條件可知,該解析只對 'family' 標簽和 'alias' 標簽裡的內容進行解析
            if (parser.getName().equals("family")) {
                config.families.add(readFamily(parser));
            } else if (parser.getName().equals("alias")) {
                config.aliases.add(readAlias(parser));
            } else {
                skip(parser);
            }
        }
        return config;
    }

從上面代碼可以知道,readFamilies針對family 和 alias 標簽裡的內容進行分析,其他內容都進行忽略處理,並且處理的結果都保存的Config這個對象中

對與family 標簽中的內容進行解析的過程,readFamily函數的調用
    private static Family readFamily(XmlPullParser parser)
            throws XmlPullParserException, IOException {

        //family 標簽可能有三個屬性: 分別是name lang variant,所以以下三行完成對對應屬性的讀取
        String name = parser.getAttributeValue(null, "name");
        String lang = parser.getAttributeValue(null, "lang");
        String variant = parser.getAttributeValue(null, "variant");

        /* 1. 以family為父標簽,font可以為其子標簽,font標簽描述的是:ttf文件的存儲路徑(path)、文字的大小(weight)、
        *     style等特性.
        *  2. family可以有多個font標簽,即在同一個family下的font是屬於同一字體族
        */ 
        List fonts = new ArrayList();

        //該循環完成對屬於同一字體族的font屬性:weight , style , fullFilename(絕對路徑)的讀取
        while (parser.next() != XmlPullParser.END_TAG) {
            if (parser.getEventType() != XmlPullParser.START_TAG) continue;
            String tag = parser.getName();
            if (tag.equals("font")) {
                String weightStr = parser.getAttributeValue(null, "weight");
                //若weight屬性不存在,默認為400
                int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
                boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
                String filename = parser.nextText();
                String fullFilename = "/system/fonts/" + filename;
                fonts.add(new Font(fullFilename, weight, isItalic));
            } else {
                skip(parser);
            }
        }
        return new Family(name, fonts, lang, variant);
    }
對 alias 標簽的內容的都取,readAlias. alias其實就是對family進行重命名(alias只能對已知的family的名字進行重命名)
eg :  名字為 sans-serif-thin的family必須在該句前出現
    private static Alias readAlias(XmlPullParser parser)
            throws XmlPullParserException, IOException {
        Alias alias = new Alias();
        alias.name = parser.getAttributeValue(null, "name");
        alias.toName = parser.getAttributeValue(null, "to");
        String weightStr = parser.getAttributeValue(null, "weight");
        if (weightStr == null) {
            alias.weight = 400;
        } else {
            alias.weight = Integer.parseInt(weightStr);
        }
        skip(parser);  // alias tag is empty, ignore any contents and consume end tag
        return alias;
    }

就這樣,就完成了對xml文件的解析

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved