Android中Typeface.createFromFile加载网络字体失败求助
你遇到的核心问题很明确:Typeface.createFromFile()只能读取本地文件系统里的字体文件,根本无法直接识别网络URL,日志里反复出现的"Font not found"就是因为你传入了一个HTTP地址,而非本地文件路径。下面是具体的问题分析和可落地的解决方案:
问题根源拆解
你的代码里直接把从Intent拿到的网络字体地址传给了createFromFile(),但这个方法的设计逻辑是仅支持本地文件的绝对路径(比如/data/data/com.nani.font/files/custom_font.otf),完全不具备网络资源加载能力,自然会抛出找不到字体的异常。
解决方案:先下载字体到本地,再加载
你需要先把网络上的字体文件下载到应用的本地存储(推荐用应用私有目录,无需动态申请存储权限),再用本地路径创建Typeface。以下是完整的实现步骤和代码示例:
1. 先添加必要权限
在AndroidManifest.xml中添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
2. 实现字体下载工具方法
写一个方法把网络字体下载到应用私有文件目录:
private File downloadFontToLocal(String fontUrl) { try { URL url = new URL(fontUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoInput(true); connection.connect(); // 用应用私有目录存储字体,无需权限 File fontFile = new File(getFilesDir(), "downloaded_font.otf"); FileOutputStream outputStream = new FileOutputStream(fontFile); InputStream inputStream = connection.getInputStream(); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, length); } // 关闭流和连接 inputStream.close(); outputStream.close(); connection.disconnect(); return fontFile; } catch (IOException e) { e.printStackTrace(); return null; } }
3. 在子线程中下载并加载字体
注意:网络请求不能在主线程执行,否则会触发ANR,这里用简单的线程实现:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_final); TextView textView = findViewById(R.id.your_textview_id); String name = getIntent().getStringExtra("name"); String fontUrl = getIntent().getStringExtra("font"); // 先设置文本内容 textView.setText(name); // 开启子线程下载字体 new Thread(() -> { File fontFile = downloadFontToLocal(fontUrl); if (fontFile != null && fontFile.exists()) { // 加载本地字体后,切回主线程更新UI Typeface tf = Typeface.createFromFile(fontFile); runOnUiThread(() -> textView.setTypeface(tf)); } else { // 下载失败提示 runOnUiThread(() -> Toast.makeText(FinalActivity.this, "字体加载失败", Toast.LENGTH_SHORT).show()); } }).start(); }
额外优化建议
- 可以加入缓存逻辑,比如记录已下载字体的URL和本地路径,避免重复下载相同字体
- 推荐用OkHttp这类成熟的网络库替代原生HttpURLConnection,简化网络请求代码
- 可以增加字体文件合法性校验,比如检查文件大小、格式是否符合OTF标准
附:你的原始代码和报错日志
原始代码
textView.setText(getIntent().getStringExtra("name")); String path= getIntent().getStringExtra("font"); Typeface tf=Typeface.createFromFile(path); textView.setTypeface(tf);
Logcat报错日志
addFont failed to create font http://server/font/public/1526331572-font.otf
05-15 14:55:51.094 4245-4245/com.nani.font E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.nani.font, PID: 4245
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.nani.font/com.nani.font.FinalActivity}: java.lang.RuntimeException: Font not found http://server/font/public/1526331572-font.otf
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2555)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2629)
at android.app.ActivityThread.access$800(ActivityThread.java:182)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1474)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5706)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1033)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:828)
Caused by: java.lang.RuntimeException: Font not found http://server/font/public/1526331572-font.otf
at android.graphics.Typeface.createFromFile(Typeface.java:250)
at com.nani.font.FinalActivity.onCreate(FinalActivity.java:29)
at android.app.Activity.performCreate(Activity.java:6092)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1112)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2502)
... 11 more
内容的提问来源于stack exchange,提问作者nani web

