Pull to refresh

Двойная буферизация или Назад в прошлое. Часть вторая

Reading time3 min
Views10K
Доброго времени суток!

Введение


На дворе уже четвёртое января, а моя душа всё не успокаивается. Поэтому я решил продолжить тему написания J2ME приложений. Плюс ко всему, несколько человек проявили нешуточный интерес к данной теме. Причём это были не только рядовые пользователи хабра, но и read-only аккаунты. Ну да ладно, ближе к теме.
Буквально сразу же после публикации топика, были получены очень дельные комментарии от хабраюзера barker, а именно замечание, по сути являющееся прописной истиной и второй комментарий — поправка, не менее дельная.


О чём мы поговорим сегодня


Сегодня мы с вами поговорим о самом процессе двойной буферизации в javax.microedition.lcdui.Canvas и о том, почему же был создан javax.microedition.lcdui.game.GameCanvas.

Что такое «двойная буферизация»


Двойная буферизация является ничем иным, как техникой, которой предусматривается использование второго (внеэкранного) буфера для отрисовки фигур, спрайтов и так далее в него, с последующим копированием его содержания в экранный. Проблема в том, что при рисовании напрямую, т.е. рисование непосредственно в экранный буфер по времени не укладывается в промежуток времени перерисовки экрана (в Canvas это осуществляется функцией repaint()) и экран попросту начинает «мигать», т.е. пользователь видит перед собой промежуточный результат этого самого рисования. Использование этой самой технике позволяет разработчику избегать этих «миганий». Тем не менее, в Canvas использование этой техники является процессом велосипедостроения, т.к. разработчики стандарта и платформы J2ME не позаботились об этом.

«Двойная буферизация» в Canvas


Процесс «двойной буферизации» в Canvas проходит с помощью использования изображения (объекта Image пакета javax.microedition.lcdui), в качестве внеэкранного буфера. Вот так:
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics; /* импортируем необходимые для работы библиотеки */
import javax.microedition.lcdui.Image;

public class OurCanvas extends Canvas {

     Image img; // наш Image
	 Graphics buf; // вот он, буфер
	 int w; // высота экрана
	 int h; // его ширина
	 
	 public OurCanvas() { // конструктор Lego
	     
		 w = getWidth(); // узнаём высоту экрана
		 h = getHeight(); // ширину
		 
		 // сначала проверяем, поддерживается ли "двойная буферизация" самим устройством
		 // если да, то и заботится о создании второго буфера нам не нужно
		 // если же нет, то создаём Image
		 if (!isDoubleBuffered()) {
		     buffer = Image.createImage(w,h);
		 }
		 
		 // получаем возможность отрисовки в img
		 buf = img.getGraphics();
     }
	 
	 // рисуем в наш буфер
	 public void draw(Graphics g) {
	     g.setColor(0xffffff);
		 g.fillRect(0,0,w,h);
		 g.setColor(0x111111);
		 g.fillRect(25,25,125,125);
		 g.setColor(0xababab);
		 g.fillRect(70,60,70,60);
	 }
	 
	 public void paint(Graphics g) {
	     g.drawImage(0,0,w,h); // рисуем сам буфер
		 draw(buf); // рисуем в буфер
	 }
}


Вот и всё. Код содержит более чем наглядные комментарии, так что разбор кода не должен вызвать у вас проблем. Теперь рассмотрим «двойную буферизацию» в GameCanvas.

«Двойная буферизация» в GameCanvas


Прошло некоторое время и J2ME консорциумом был разработан пакет javax.microedition.lcdui.game, в котором содержался GameCanvas, который представлял собой всё тот же Canvas, но уже с решённой проблемой «двойной буферизации». Программистам теперь не нужно о ней заботиться. Код же будет выглядеть следующим образом:
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.Graphics; /* импортируем необходимые для работы библиотеки */
import javax.microedition.lcdui.Image;

public class OurCanvas extends GameCanvas implements Runnable {

     Graphics buf;
	 Thread t;
	 int w; // высота экрана
	 int h; // его ширина
	 
	 public OurCanvas() { // конструктор нашего OurCanvas
	     
		 w = getWidth(); // узнаём высоту экрана
		 h = getHeight(); // ширину
		 
		 // получаем ссылку на объект Graphics
		 buf = getGraphics();
		 
		 // наша нить
		 t = new Thread(this);
     }
	 
	 // let's draw
	 public void run {
	     g.setColor(0xffffff);
		 g.fillRect(0,0,w,h);
		 g.setColor(0x111111);
		 g.fillRect(25,25,125,125);
		 g.setColor(0xababab);
		 g.fillRect(70,60,70,60);
		 flushGraphics(); // вот и вся наша "двойная буферизация"
	 }
}

Тут нам не нужно заботиться о буфере — всё сразу рисуется в него, а затем при вызове flushGraphics всё содержимое внеэкранного буфера копируется в экранный.

На этом всё


Несмотря на то, что данная задача отрисовки решается в несколько строк — это достаточно важная тема, в которой разработчикам нельзя «плавать». Надеюсь, сегодняшний урок был не менее поучительным, чем прошлый. На этом всё, разрешите откланяться.

До скорых встреч!

Пейте кофе, пишите на Java.


Post Scriptum


Исходники по сложившейся традиции вы можете забрать на Pastebin.
Здесь — первый пример.
И здесь — второй.
Tags:
Hubs:
Total votes 17: ↑14 and ↓3+11
Comments51

Articles