*概述 ---SWT中创建的与操作系统相关的资源需要手动释放,如Image,Font,GC等,从api的角度看,就是org.eclipse.swt.graphics.Resource的所有子类. 所以...
*概述
---SWT中创建的与操作系统相关的资源需要手动释放,如Image,Font,GC等,从api的角度看,就是org.eclipse.swt.graphics.Resource的所有子类.
所以对于需要重复利用的资源,我们一般做法是定义一个Map管理这些资源,最后再释放,如下面的做法
ColorManager示例 /*
* Copyright(C) 2010 Agree Tech, All rights reserved.
*
* Created on 2010-9-7 by dzh
*/
package cn.com.agree.modeling;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
public class ColorManager {
private final Map<RGB,Color> colorMap =new HashMap<RGB,Color>();
public Color getColor(RGB rgb){
Color color =(Color) colorMap.get(rgb);
if(color==null){
color =new Color(Display.getDefault(),rgb);
colorMap.put(rgb, color);
}
return color;
}
public void dispose(){
Iterator<Color> i =colorMap.values().iterator();
while(i.hasNext()){
i.next().dispose();
}
colorMap.clear();
}
}
---还有另外一种方式,利用SWT的特性:每个SWT程序,都有一个Display对象,Display在UI开始时被创建,在程序结束时被释放,咱们看看Display提供了些什么.
*实现原理
---display释放调用过程分析
Device.dispose()->Display.release()->Display.disposeList执行,
Display片段/* Display Shutdown */
Runnable [] disposeList;//这是Display定义的一个数组
protected void release () {
sendEvent (SWT.Dispose, new Event ());
Shell [] shells = getShells ();
for (int i=0; i<shells.length; i++) {
Shell shell = shells [i];
if (!shell.isDisposed ()) shell.dispose ();
}
if (tray != null) tray.dispose ();
tray = null;
if (taskBar != null) taskBar.dispose ();
taskBar = null;
while (readAndDispatch ()) {}
if (disposeList != null) {
for (int i=0; i<disposeList.length; i++) { //执行disposeList内容
if (disposeList [i] != null) disposeList [i].run ();
}
}
disposeList = null;
synchronizer.releaseSynchronizer ();
synchronizer = null;
releaseDisplay ();
super.release ();
}
---现在知道了,只要给数组添加java.lang.Runnable,在Runnable.run()实现资源释放,这样就实现了我们缓存和自动释放的目的.
添加Runnable/**
* Causes the <code>run()</code> method of the runnable to
* be invoked by the user-interface thread just before the
* receiver is disposed. Specifying a <code>null</code> runnable
* is ignored.
*
* @param runnable code to run at dispose time.
*
* @exception SWTException <ul>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
* </ul>
*/
public void disposeExec (Runnable runnable) { //添加runnable
checkDevice ();
if (disposeList == null) disposeList = new Runnable [4];
for (int i=0; i<disposeList.length; i++) {
if (disposeList [i] == null) {
disposeList [i] = runnable;
return;
}
}
Runnable [] newDisposeList = new Runnable [disposeList.length + 4];
System.arraycopy (disposeList, 0, newDisposeList, 0, disposeList.length);
newDisposeList [disposeList.length] = runnable;
disposeList = newDisposeList;
}
*示例分析
---jface根据上面介绍的原理,在org.eclipse.jface.resource下提供了对需要释放资源的缓存类
---以org.eclipse.jface.resource.ColorRegistry为例,看看实现方式
ColorRegistry示例 /**
* Collection of <code>Color</code> that are now stale to be disposed when
* it is safe to do so (i.e. on shutdown).
*/
private List staleColors = new ArrayList(); //缓存资源
/**
* Table of known colors, keyed by symbolic color name (key type: <code>String</code>,
* value type: <code>org.eclipse.swt.graphics.Color</code>.
*/
private Map stringToColor = new HashMap(7);
/**
* Runnable that cleans up the manager on disposal of the display.
*/
//定义Runnable
protected Runnable displayRunnable = new Runnable() {
public void run() {
clearCaches(); //释放资源
}
};
public ColorRegistry(Display display, boolean cleanOnDisplayDisposal) {
Assert.isNotNull(display);
this.display = display;
this.cleanOnDisplayDisposal = cleanOnDisplayDisposal;
if (cleanOnDisplayDisposal) {
hookDisplayDispose(); //将runnable添加到Display释放数组中
}
}
/**
* Hook a dispose listener on the SWT display.
*/
private void hookDisplayDispose() {
display.disposeExec(displayRunnable);
}
*总结
---由于资源创建过多,没有及时释放,或者遗漏需要释放的资源,会导致"no more handlers"异常,以致程序崩溃.
所以缓存能提升性能,避免忘记释放,但是要注意在恰当的时候就及时释放.