简短回答: 不,它不支持(截止到JavaFX 2.x和8.0版本)。或许在未来的版本中会支持(JFX >8)。
详细回答:FXMLLoader当前没有被设计成为一个模板提供者,用于重复实例化相同的项目。相反,它旨在成为大型GUI的一次性加载器(或用于序列化它们)。
由于FXML文件的不同,每次调用
load()
时性能都很差,因为FXMLLoader必须通过反射查找类及其属性。这意味着:
- 对于每个import语句,请尝试加载每个类,直到类可以成功加载。
- 对于每个类,创建一个BeanAdapter,查找此类具有的所有属性,并尝试将给定参数应用于该属性。
- 再次通过反射将参数应用于属性。
目前也没有针对代码中对同一FXML文件进行后续调用时的任何改进。这意味着:没有缓存找到的类,没有缓存BeanAdapters等。
然而,有一个步骤1的性能解决方法,即为FXMLLoader实例设置自定义类加载器:
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
public class MyClassLoader extends ClassLoader{
private final Map<String, Class> classes = new HashMap<String, Class>();
private final ClassLoader parent;
public MyClassLoader(ClassLoader parent) {
this.parent = parent;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class<?> c = findClass(name);
if ( c == null ) {
throw new ClassNotFoundException( name );
}
return c;
}
@Override
protected Class<?> findClass( String className ) throws ClassNotFoundException {
if (classes.containsKey(className)) {
Class<?> result = classes.get(className);
return result;
} else {
try {
Class<?> result = parent.loadClass(className);
classes.put(className, result);
return result;
} catch (ClassNotFoundException ignore) {
classes.put(className, null);
return null;
}
}
}
@Override
public URL getResource( String name ) {
return parent.getResource(name);
}
@Override
public Enumeration<URL> getResources( String name ) throws IOException {
return parent.getResources(name);
}
@Override
public String toString() {
return parent.toString();
}
@Override
public void setDefaultAssertionStatus(boolean enabled) {
parent.setDefaultAssertionStatus(enabled);
}
@Override
public void setPackageAssertionStatus(String packageName, boolean enabled) {
parent.setPackageAssertionStatus(packageName, enabled);
}
@Override
public void setClassAssertionStatus(String className, boolean enabled) {
parent.setClassAssertionStatus(className, enabled);
}
@Override
public void clearAssertionStatus() {
parent.clearAssertionStatus();
}
}
使用方法:
public static ClassLoader cachingClassLoader = new MyClassLoader(FXMLLoader.getDefaultClassLoader())
FXMLLoader loader = new FXMLLoader(resource)
loader.setClassLoader(cachingClassLoader)
这极大地提高了性能。然而,第二步没有解决办法,因此这可能仍然是一个问题。
不过,官方的JavaFX jira中已经有了相关功能请求。如果您能支持这些请求,那就太好了。
链接: