自定义字体TextView的性能问题

23

我有一个自定义的TextView,带有个性化字体属性:

public class TextViewPlus extends TextView {
    private static final String TAG = "TextViewPlus";
    public TextViewPlus(Context context) {
        super(context);
    }
    public TextViewPlus(Context context, AttributeSet attrs) {
        // This is called all the time I scroll my ListView
        // and it make it very slow. 
        super(context, attrs);
        setCustomFont(context, attrs);
    }
    public TextViewPlus(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setCustomFont(context, attrs);
    }
    private void setCustomFont(Context ctx, AttributeSet attrs) {
        TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.TextViewPlus);
        String customFont = a.getString(R.styleable.TextViewPlus_customFont);
        setCustomFont(ctx, customFont);
        a.recycle();
    }
    public boolean setCustomFont(Context ctx, String asset) {
        Typeface tf = null;
        try {
            tf = Typeface.createFromAsset(ctx.getAssets(), asset);  
            setTypeface(tf); 
        } catch (Exception e) {
            Log.e(TAG, "Could not get typeface: "+e.getMessage());
            return false;
        }
        return true;
    }
}

我在我的XML文件中使用它,属性为customFont="ArialRounded.ttf",效果非常好。

我在ListView中使用这个TextViewPlus,用一个ArrayAdapter来填充。

TextViewPlus dataText = (TextViewPlus) itemView.findViewById(R.id.data_text);
dataText.setText("My data String");

我的问题是,当我滚动ListView时,性能非常差!非常缓慢而且充满延迟。每次我滚动列表时,都会调用TextViewPlus构造函数n°2。

如果我将TextViewPlus更改为普通的TextView,并使用dataText.setTypeface(myFont),一切都很顺利,运行良好。

如何使用我的TextViewPlus而没有性能问题?


2
你尝试过将 Typeface 缓存到某个地方,这样它就不需要每次都重新创建了吗? - jprofitt
我现在做了。我尝试了Praful Bhatnagar的解决方案,它非常有效。 - Nifhel
1个回答

37

为何不将已创建的typface对象保存在内存中,这样每次创建文本视图时就无需再次创建。

以下是一个示例类,用于创建并缓存typeface对象:

public class TypeFaceProvider {

    public static final String TYPEFACE_FOLDER = "fonts";
    public static final String TYPEFACE_EXTENSION = ".ttf";

    private static Hashtable<String, Typeface> sTypeFaces = new Hashtable<String, Typeface>(
        4);

    public static Typeface getTypeFace(Context context, String fileName) {
    Typeface tempTypeface = sTypeFaces.get(fileName);

    if (tempTypeface == null) {
        String fontPath = new StringBuilder(TYPEFACE_FOLDER).append('/').append(fileName).append(TYPEFACE_EXTENSION).toString();
        tempTypeface = Typeface.createFromAsset(context.getAssets(), fontPath);
        sTypeFaces.put(fileName, tempTypeface);
    }

    return tempTypeface;
    }
}

我很高兴它能正常工作,但是如果你正确实现了你的ListView适配器,缓存不应该给你任何性能提升。也就是说,视图(包括TextView)被正确地重用。如果它们被正确地重用,那么在滚动期间就不应该再加载.ttf文件了。 - Zsolt Safrany
@Zsolt Safrany,抱歉但那不是完全正确的。如果不影响滚动,则会影响页面加载时间。假设您有7个可见项目,每个项目有3个文本视图,则将从资产中加载21次字体,这非常糟糕。 - Hamzeh Soboh
@HamzehSoboh 这是一个很好的观点 - 我没有考虑过这个。 - Zsolt Safrany
如何使用这个类? - Iman Marashi
@PrafulBhatnagar 非常感谢,兄弟。我在RecyclerViewViewpager中使用自定义字体。RecyclerView的一个项目有两种字体,而ViewPager选项卡标题有两种字体(一种用于选定,另一种用于禁用),我一直在想为什么我的应用程序在滚动和滑动时很慢,今天我意识到了这一点,并开始寻找解决方案,最终来到了这里。 - Praveena

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接