[关闭]
@linux1s1s 2017-01-22T08:50:37.000000Z 字数 2602 阅读 2130

Android 字体内存泄露

AndroidMemory 2016-06


字体需求

在App开发中,一般都会使用自定义的字体,这些字体美化App的同时,可能还会带来额外的问题,最容易带来的问题就是内存泄露,这里举个实际中遇到的问题作为例子

如果需要在Title、Price上做自定义字体。假如我们这么处理这个需求

  1. Typeface tf=Typeface.createFromAsset(getAssets(), Consts.LANTING_FONT_PATH);
  2. title.setTypeface(tf);
  1. Typeface tf=Typeface.createFromAsset(getAssets(), Consts.LANTING_FONT_PATH);
  2. price.setTypeface(tf);

像上面这么处理,进入这个页面以后,在滚动View的时候会明显卡顿 1S左右, 用户体验相当不好。
接下来看看问题在哪里
跑monkey测试:

发现问题

adb shell dumpsys meminfo 【packgename】

此命令会打出当前应用内存占用情况,如下:

此处输入图片的描述
此处输入图片的描述

注意很明显的/assets/fonts/fzlthjw.ttf 出现的N多次,而且每次都是2,M多,这个内存占用相当的恐怖了,很明显出现了内存泄露

那么该如何解决?

解决问题

解决的办法比较简单,因为 Typeface.createFromAsset(...)是个高消耗方法,缓存使用即可。

比如像这样:

  1. protected static final Typeface TYPEFACE = Typeface.createFromAsset(
  2. application.getAssets(), "fonts/fzlthjw.ttf");
  3. titile.setTypeface(TYPEFACE );
  4. price.setTypeface(TYPEFACE );

然后我们再次用monkey测试一下:

此处输入图片的描述

问题得以解决

推荐方法

不过建议上面的Typeface用Manager管理起来,防止不恰当使用引起内存泄露,下面给个简单的Manager类以供参考:

  1. import java.util.HashMap;
  2. import java.util.Map;
  3. import android.app.Application;
  4. import android.content.res.AssetManager;
  5. import android.graphics.Typeface;
  6. public class FontManager {
  7. private static FontManager FONT_MANAGER;
  8. private AssetManager mAssetManager;
  9. private static final Map<String, Typeface> CACHE_FONT_MAP = new HashMap<String, Typeface>();
  10. private FontManager(Application application) {
  11. mAssetManager = application.getAssets();
  12. }
  13. public static void createInstance(Application application) {
  14. if (FONT_MANAGER == null) {
  15. synchronized (FontManager.class) {
  16. if (FONT_MANAGER == null) {
  17. FONT_MANAGER = new FontManager(application);
  18. }
  19. }
  20. }
  21. }
  22. public static FontManager getInstance() {
  23. if (FONT_MANAGER == null) {
  24. throw new NullPointerException("NullPoint Exception, Please call createInstance first!");
  25. }
  26. return FONT_MANAGER;
  27. }
  28. public Typeface getFont(FontType type) {
  29. if (type == null) {
  30. return null;
  31. }
  32. final String key = type.getValue();
  33. Typeface typeface = null;
  34. switch (type) {
  35. case TANG_SH:
  36. if (CACHE_FONT_MAP.containsKey(key)) {
  37. return CACHE_FONT_MAP.get(key);
  38. } else {
  39. typeface = Typeface.createFromAsset(mAssetManager, "fonts/fzlthjw.ttf");
  40. CACHE_FONT_MAP.put(key, typeface);
  41. }
  42. break;
  43. default:
  44. break;
  45. }
  46. return typeface;
  47. }
  48. public static enum FontType {
  49. TANG_SH("tang_sh");
  50. String value;
  51. FontType(String value) {
  52. this.value = value;
  53. }
  54. public String getValue() {
  55. return value;
  56. }
  57. }
  58. // -----------------------------------------------------------------------
  59. // Convenient
  60. // -----------------------------------------------------------------------
  61. public static class FLFont {
  62. public static Typeface getFont(FontType type) {
  63. try {
  64. FontManager manager = FontManager.getInstance();
  65. return manager.getFont(type);
  66. } catch (NullPointerException e) {
  67. e.printStackTrace();
  68. }
  69. return null;
  70. }
  71. }
  72. }

调用的时候在Application中初始化一次

  1. FontManager.createInstance(this);

然后在使用的时候:

  1. title.setTypeface(FLFont.getFont(FontType.TANG_SH))

这样就可以全局避免内存泄露。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注