我寫了程序本來想在NOkia 6108上比較用和不用的區別,結果這個手機自己就支持雙緩沖,所以根本沒有比較出來。不過了解這個技術還是有必要的,所以我決定還是寫出來。雙緩沖本來是在開發PC應用程序的時候遇到的。在MIDP開發中同樣存在,當你在屏幕上進行原始寫畫的時候,如果很復雜的話,用戶會發現界面在閃爍。因此你可以這樣做,首先在另一個圖片上進行paint()得操作,當完成了以後就把它copy到屏幕上,由於通常copy得時候速度很快就不會出現閃爍了。這個技術就是雙緩沖。
Canvas類提供了isDoubleBuffered()方法來判斷設備是不是支持這個功能,如果返回true的話,那麼我們就沒有必要使用雙緩沖了,如果false的話,我們可以這麼做:
public DoubleCanvas(UIController uicontroller)
{
super();
this.uicontroller = uicontroller;
width = this.getWidth();
height = this.getHeight();
this.setCommandListener(this);
if(!isDoubleBuffered())
{
offImage = Image.createImage(width,height);
}
}
protected void paint(Graphics arg0)
{
arg0.drawString(isDoubleBuffered()+"",width/2,height/2,Graphics.HCENTER|Graphics.TOP);
Graphics saved = arg0;
if(offImage != null)
{
arg0 = offImage.getGraphics();
}
arg0.setColor(255,128,128);
for(int i = 2,j=2;i<width/2-6&&j<height/2-6;i=i+2,j=j+2)
{
arg0.drawRect(i,j,width-2*i,height-2*j);
}
if(arg0 != saved)
{
saved.drawImage(offImage,0,0,Graphics.LEFT|Graphics.TOP);
}
}
得到offImage得Graphics實例後,進行paint()得操作。這個部分通常比較復雜,我這裡的不夠復雜:)
然後把offImage直接copy到屏幕上也就是執行saved.drawImage(offImage,0,0,Graphics.LEFT|Graphics.TOP);
我寫了一個應用程序來比較使用和不使用雙緩沖的效果,但是由於我的手機支持雙緩沖所以看不出效果,如果你有興趣,那麼可以把paint()部分的代碼修改的復雜一些然後再移植到不支持的手機上也許可以看出效果,下面是我程序的代碼:
import Javax.microedition.midlet.MIDlet;
import Javax.microedition.midlet.MIDletStateChangeException;
public class DoubleBufferMIDlet extends MIDlet
{
private UIController uicontroller;
protected void startApp() throws MIDletStateChangeException
{
uicontroller = new UIController(this);
uicontroller.init();
}
protected void pauseApp()
{
}
protected void destroyApp(boolean arg0) throws MIDletStateChangeException
{
}
}
import Javax.microedition.lcdui.Command;
import Javax.microedition.lcdui.CommandListener;
import Javax.microedition.lcdui.Displayable;
import Javax.microedition.lcdui.List;
public class MainListUI extends List implements CommandListener
{
private UIController uicontroller;
public MainListUI(UIController uicontroller)
{
super("Test",List.IMPLICIT);
this.uicontroller = uicontroller;
this.append("Non-buffer",null);
this.append("Double-buffer",null);
this.setCommandListener(this);
}
public void commandAction(Command arg0, Displayable arg1)
{
if(arg0 == List.SELECT_COMMAND)
{
if(this.getSelectedIndex() == 0)
{
uicontroller.handleEvent(UIController.EventID.DISPLAY_NON_BUFFER);
}
else
{
uicontroller.handleEvent(UIController.EventID.DISPLAY_BUFFER);
}
}
}
}
import Javax.microedition.lcdui.Command;
import Javax.microedition.lcdui.CommandListener;
import Javax.microedition.lcdui.Display;
import Javax.microedition.lcdui.Displayable;
public class UIController implements CommandListener
{
private Display display;
private DoubleBufferMIDlet midlet;
private MainListUI mainList;
private NonDoubleCanvas noDoubleCanvas;
private DoubleCanvas doubleCanvas;
public static final Command backCommand = new Command("Back",Command.BACK,2);
public static class EventID
{
public static final int DISPLAY_NON_BUFFER = 0;
public static final int DISPLAY_BUFFER = 1;
}
public UIController(DoubleBufferMIDlet midlet)
{
this.midlet = midlet;
}
public void init()
{
display = Display.getDisplay(midlet);
mainList = new MainListUI(this);
noDoubleCanvas = new NonDoubleCanvas(this);
doubleCanvas = new DoubleCanvas(this);
addCommand();
display.setCurrent(mainList);
}
public void addCommand()
{
noDoubleCanvas.addCommand(backCommand);
doubleCanvas.addCommand(backCommand);
}
public Display getDisplay()
{
return display;
}
public void setCurrent(Displayable disp)
{
display.setCurrent(disp);
}
public void handleEvent(int eventID)
{
switch(eventID)
{
case EventID.DISPLAY_BUFFER:
{
setCurrent(doubleCanvas);
System.out.println(EventID.DISPLAY_BUFFER);
break;
}
case EventID.DISPLAY_NON_BUFFER:
{
setCurrent(noDoubleCanvas);
System.out.println(EventID.DISPLAY_NON_BUFFER);
break;
}
}
}
public void commandAction(Command arg0, Displayable arg1)
{
if(arg0 == backCommand)
{
display.setCurrent(mainList);
}
}
}
import Javax.microedition.lcdui.Canvas;
import Javax.microedition.lcdui.Command;
import Javax.microedition.lcdui.CommandListener;
import Javax.microedition.lcdui.Displayable;
import Javax.microedition.lcdui.Graphics;
public class NonDoubleCanvas extends Canvas implements CommandListener
{
private UIController uicontroller;
private int width;
private int height;
public NonDoubleCanvas(UIController uicontroller)
{
super();
this.uicontroller = uicontroller;
width = this.getWidth();
height = this.getHeight();
this.setCommandListener(this);
}
protected void paint(Graphics arg0)
{
arg0.setColor(100,100,100);
arg0.drawString(isDoubleBuffered()+"",width/2,height/2,Graphics.HCENTER|Graphics.TOP);
for(int i = 2,j=2;i<width/2-6&&j<height/2-6;i=i+2,j=j+2)
{
arg0.drawRect(i,j,width-2*i,height-2*j);
}
}
public void commandAction(Command arg0, Displayable arg1)
{
uicontroller.commandAction(arg0,arg1);
}
}
import Javax.microedition.lcdui.Canvas;
import Javax.microedition.lcdui.Command;
import Javax.microedition.lcdui.CommandListener;
import Javax.microedition.lcdui.Displayable;
import Javax.microedition.lcdui.Graphics;
import Javax.microedition.lcdui.Image;
public class DoubleCanvas extends Canvas implements CommandListener
{
private UIController uicontroller;
private Image offImage;
private int width;
private int height;
public DoubleCanvas(UIController uicontroller)
{
super();
this.uicontroller = uicontroller;
width = this.getWidth();
height = this.getHeight();
this.setCommandListener(this);
if(!isDoubleBuffered())
{
offImage = Image.createImage(width,height);
}
}
protected void paint(Graphics arg0)
{
arg0.drawString(isDoubleBuffered()+"",width/2,height/2,Graphics.HCENTER|Graphics.TOP);
Graphics saved = arg0;
if(offImage != null)
{
arg0 = offImage.getGraphics();
}
arg0.setColor(255,128,128);
for(int i = 2,j=2;i<width/2-6&&j<height/2-6;i=i+2,j=j+2)
{
arg0.drawRect(i,j,width-2*i,height-2*j);
}
if(arg0 != saved)
{
saved.drawImage(offImage,0,0,Graphics.LEFT|Graphics.TOP);
}
}
public void commandAction(Command arg0, Displayable arg1)
{
uicontroller.commandAction(arg0,arg1);
}
}