Android字体工作原理与应用

       Android字体系统由android 2D图形引擎skia实现,字体系统的配置方法在各个版本中不完全相同,按照API level可以划分为三个阶段:4.0以下版本、4.0-4.4版本、5.0及以上版本。本文主要针对4.0及以上版本中字体系统的配置方法及字体相关应用进行分析。注意,浏览器及webView中的字体有单独的字体系统。     
     Android中将每个字体文件描述为字型(Typeface),包括字体族(FontFamily)和字体样式(textStyle)两个维度,字体族对应各种字体类型,样式则分为normal、bold、italic和bold-italic四种。
     

工作原理

   下面对字体工作原理的分析围绕系统字体配置文件解析与字体加载相关内容,不涉及skia的实现细节,为便于理解分为三个部分。

1. java层
     在这一层,android.graphics.Typeface类负责加载系统字体,并对上层提供创建字体功能调用。下面分析Typeface类的调用过程。
     在android启动过程中,ZygoteInit类的入口函数main()中调用preload()函数,preload()函数主要用于加载并初始化各种类、链接库、资源等。
static void preload() {
        Log.d(TAG, "begin preload");
        preloadClasses();
        preloadResources();
        preloadOpenGL();
        preloadSharedLibraries();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();
        Log.d(TAG, "end preload");
}
     在preload()中调用了preloadClasses()函数用于加载并初始化一些系统常用类,这些类的列表位于frameworks/base/preloaded-classes文件中,其中包括了Typeface类。
/**
* Performs Zygote process initialization. Loads and initializes
* commonly used classes.
*
* Most classes only cause a few hundred bytes to be allocated, but
* a few will allocate a dozen Kbytes (in one case, 500+K).
*/
private static void preloadClasses() {
    ......
    InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(PRELOADED_CLASSES);
     
    ......
 
    try {
                BufferedReader br = new BufferedReader(new InputStreamReader(is), 256);
 
                int count = 0;
                String line;
                while ((line = br.readLine()) != null) {
                    // Skip comments and blank lines.
                    line = line.trim();
                    if (line.startsWith("#") || line.equals("")) {
                        continue;
                    }
 
                    try {
                        if (false) {
                            Log.v(TAG, "Preloading " + line + "...");
                        }
                        Class.forName(line);
 
    ......
}
     preloadClasses()中调用Class.forName("android.graphics.Typeface")加载Typeface类,并调用Typeface类的static块。create()通过调用相应的native方法创建字体对象。
// 4.x
    static {
        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 native int  nativeCreate(String familyName, int style);
    private static native int  nativeCreateFromTypeface(int native_instance, int style);
    private static native void nativeUnref(int native_instance);
    private static native int  nativeGetStyle(int native_instance);
    private static native int  nativeCreateFromAsset(AssetManager mgr, String path);
    private static native int nativeCreateFromFile(String path);
 
 
// 5.x
    static {
        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 native long nativeCreateFromTypeface(long native_instance, int style);
    private static native long nativeCreateWeightAlias(long native_instance, int weight);
    private static native void nativeUnref(long native_instance);
    private static native int  nativeGetStyle(long native_instance);
    private static native long nativeCreateFromArray(long[] familyArray);
    private static native void nativeSetDefault(long native_instance);
     注意4.x版本与5.x版本提供的上层API调用是一致的,但是c++层的native函数却并不一致,这与5.x版本中static块增加了一个init()函数调用有关,init()方法主要实现了解析系统字体配置文件,并据此加载系统字体。对于4.x版本,解析并加载系统字体的功能在c++层的skia代码中实现,留到下面进行分析。
private static void init() {
        // Load font config and initialize Minikin state
        File systemFontConfigLocation = getSystemFontConfigLocation();
        File configFilename = new File(systemFontConfigLocation, F
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Android应用广播是一种机制,用于在应用程序之间或应用程序的组件之间传递消息。以下是Android应用广播的工作原理: 1. 定义广播接收器:在Android应用程序中,需要定义一个广播接收器,该接收器定义了要接收的广播消息的类型。 2. 注册广播接收器:在应用程序中,需要在代码中注册广播接收器,以便系统知道哪些广播接收器对哪些广播感兴趣。 3. 发送广播:在应用程序中,需要使用Intent对象发送广播消息。可以使用系统预定义的广播消息,或者可以定义自己的广播消息。 4. 接收广播:当广播消息发送时,系统会通知所有注册的广播接收器,并将广播消息传递给它们。广播接收器会对广播消息进行处理,并执行相应的操作。 以下是一个简单的Android应用广播程序的示例代码: 1. 定义广播接收器 ```java public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 处理广播消息 String message = intent.getStringExtra("message"); Toast.makeText(context, "Received message: " + message, Toast.LENGTH_SHORT).show(); } } ``` 2. 注册广播接收器 ```java IntentFilter filter = new IntentFilter("com.example.MY_BROADCAST"); registerReceiver(new MyBroadcastReceiver(), filter); ``` 3. 发送广播 ```java Intent intent = new Intent("com.example.MY_BROADCAST"); intent.putExtra("message", "Hello, world!"); sendBroadcast(intent); ``` 在此示例中,我们定义了一个名为"MyBroadcastReceiver"的广播接收器,并在应用程序中注册了它。我们还定义了一个名为"com.example.MY_BROADCAST"的广播消息,并使用Intent对象将它发送到所有已注册的广播接收器。当广播消息发送时,我们的广播接收器会接收到它,并显示一个Toast消息,以显示接收到的消息内容。 请注意,此示例仅涵盖了Android应用广播的基本概念。在实际应用程序中,可能需要更复杂的广播消息处理逻辑和更高级的广播接收器注册和管理方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值