在我们的android应用中,我们具有以下要求
到目前为止,我们有一个简单的单例,看起来像这样:
@NotThreadSafe
public static void init(Context context) {
if (instance == null) {
instance = new TypefaceHelper(context);
instance.setAssetManager(context.getAssets());
instance.setAllTypefaces();
}
}
以下是我遇到的问题:
因此,每次调用MyApplication(扩展了Android应用程序的扩展)时,我们的字体初始化本身都需要50毫秒以上的时间。
作为性能调整的一部分,我们认为在后台加载字体是有意义的。因此,现在我想在后台加载字体,并确保初始化线程安全。
这是我想出的设计
public class TypefaceHelper {
private static TypefaceHelper instance;
private volatile Typeface proximaRegular;
private final Object typefaceLock = new Object();
private static final Object constructorLock = new Object();
@GuardedBy("constructorLock")
public static void init(Context context) {
synchronized (constructorLock) {
if (instance == null) {
instance = new TypefaceHelper(context);
instance.setAssetManager(context.getAssets());
MyApplicationHelper.getInstance().getExecutorService().execute(new Runnable() {
@Override
public void run() {
instance.setAllTypefaces(); // Set up all Typefaces in background thread
}
});
}
}
}
@Nullable
public static TypefaceHelper getInstance() { // Existing code used in 100+ places. Not touched now.
return instance;
}
// Accessing a typeface. Use Double-checked locking to ensure it works
public Typeface getProximaRegular() {
if(proximaRegular==null){ // The variable must be volatile to prevent compiler re-orderings and optimizations
synchronized (typefaceLock){
if(proximaRegular==null){
proximaRegular = Typeface.createFromAsset(assetManager, "fonts/ProximaNova-Regular.otf");
}
}
}
return proximaRegular;
}
@GuardedBy("typefaceLock")
private void setAllTypefaces(){
synchronized (typefaceLock) {
proximaRegular = Typeface.createFromAsset(assetManager, "fonts/ProximaNova-Regular.otf");
// Initialize 3 other typefaces here
}
}
}
请注意,我正在getProxmimaRegular()中的同步块外使用空检查,因为它是从100多个地方访问的,如果它不为空,我不希望获得锁。
我的问题是:
1)在后台加载单例的成员变量是否不好? (否则性能会受到很大影响)
2)在这里为init()使用单独的锁在这里过大了吗?
3)考虑到我的要求,我该如何使其更好?