戌印-INUJIRUSHI- (Androidあれこれ)

Androidのプログラミングをメインにしてます。記事に貼られたソースコードはダブルクリックすることで行番号をはずしてコピーすることができます。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
08

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

SurfaceViewとダブルバッファリング

参考サイト:Waku Waku Java - 講座1 ダブルバッファリング

ダブルバッファリングとは、画面のちらつきを防ぐための技術です。

一般的な描画は、画面を一度クリア(もしくは塗りつぶし)してから背景、キャラクターと描いていきます。
キャラクターを動かしたりなどのアニメーションを行うときはコレを繰り返し行います。

通常の描画の場合、画面に直接描画を行っています。
そのため、画面をクリアした際に何も無い画面が一瞬見えてしまうために画面がちらついて見えてしまうことがあります。

そこでダブルバッファリングの出番です。
ダブルバッファリングでは、表示されている画面とは別に、裏にもう一つの画面(オフスクリーン・バッファ)を持ちます。
裏の画面で描画を行い、描画が完成したら表の画面と入れ替えることで描画している姿を見せないようにしています。
これによりクリアされた画面が見えないためにちらつきを防ぐことができます。

図1:
double_buffe.png


さて、ここから SurfaceView の話。
(正確にはダブルバッファリングの使い方、かな?)
【関連記事】描画Viewクラス : SurfaceView

SurfaceViewを使っているのに描画がちらついて見える、という方がいると思います。
ダブルバッファリングを行っているんだからちらつかないよね?と思う方もいると思いますが、これはCanvasが2つ存在していることに原因があります。

2つのCanvasは独立しており、片方のCanvasに描画した内容は、もう片方のCanvasに反映されません。

毎回1から描画をする場合には問題にならないことですが、お絵かきツールのようにCanvasに追記していく場合に問題になります。

たとえば、先ほどの神父さんが道を歩いていたら、突然人に襲われたとします。
最初は神父さん一人だけでしたが、後で襲撃者を追記します。
この場合、SurfaceViewで普通に描くと図2のようになります。

図2:
double_buffe2.png

最初のCanvas(以下、Canvas1)には神父さんがいますが、追記された襲撃者は別のCanvas(以下、Canvas2)に描画されているためこのような現象が発生します。
スレッドなどで描画を繰り返している場合、別々の絵が描かれたCanvas1とCanvas2が交互に表示されるためにちらつきが発生してしまいます。


この問題の対策としては、2つのCanvasに共通するバッファを持つことです。
共通するバッファ(ここではBitmap)に描画を行い、最後にバッファを対象となるCanvasに描きだす(図3)。
これでCanvas1とCanvas2の差はなくなり、ちらつきがなくなります。
(Canvas2 には Canvas1 + 追記分)

図3:
double_buffe3.png

以上で、SurfaceViewとダブルバッファリングの説明は終了です。

最後に、追記型描画のちらつき対応を行ったサンプルソースコードを載せます。
このサンプルでは1~10の数値を画面のランダム位置に描画します。
(図と関係ないプログラム)
package jp.inujirushi.sample.activity;

import java.util.Random;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class SurfaceViewActivity extends Activity {

/** アクティビティを生成した時に呼ばれます。 */
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SampleSurfaceView(this));
}

/**
* SurfaceView 拡張クラス
*/
class SampleSurfaceView extends SurfaceView implements
SurfaceHolder.Callback, Runnable {
// 描画情報
SurfaceHolder mHolder;
Thread mThread;
Bitmap mBitmap;

/**
* コンストラクタ
*
* @param context
*/
public SampleSurfaceView(Context context) {
super(context);

// Holderを取得する
mHolder = getHolder();

// SurfaceViewにコールバックを追加(開始)する
mHolder.addCallback(this);
}

/**
* SurfaceViewが生成されたときに呼ばれます。
*/
@Override
public void surfaceCreated(SurfaceHolder holder) {
// オフスクリーン用のBitmapを生成する
mBitmap = Bitmap.createBitmap(getWidth(), getHeight(),
Config.ARGB_8888);

// スレッドを開始する
mThread = new Thread(this);
mThread.start();
}

/**
* SurfaceViewの状態が変更されたときに呼ばれます。
* SurfaceViewが生成されたときにも呼ばれます。
*/
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}

/**
* SurfaceViewが破棄されるときに呼ばれます。
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// スレッドを破棄する
mThread = null;

// Bitmapを解放する
if (mBitmap != null)
mBitmap.recycle();
}

/**
* スレッド処理を行います
*/
@Override
public void run() {
// メイン処理(1~10まで描画)
for (int i = 1; i <= 10; i++) {
// Canvasをロックして取得する
Canvas canvas = mHolder.lockCanvas();

// オフスクリーンバッファに描画する
if (mBitmap != null) {
// オフスクリーンバッファを生成する
Canvas offScreen = new Canvas(mBitmap);

// オフスクリーンバッファに書き込む
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(30);
int x = new Random().nextInt(100) * (getWidth() / 100);
int y = new Random().nextInt(100) * (getHeight() / 100);
offScreen.drawText("" + i, x, y, paint);
}

// オフスクリーンバッファを描画する
canvas.drawBitmap(mBitmap, 0, 0, null);

// Canvasのロックを解除する
mHolder.unlockCanvasAndPost(canvas);
}
}
}
}
※107行目でオフスクリーン・バッファに対して描画を行っています。
 これをロックしたキャンバス(94行目)に対して行った場合、偶数しか表示されなくなります。
スポンサーサイト

Comments

Leave a Comment


Body
プロフィール

とむ・やむくん

Author:とむ・やむくん
管理人について

Windows 7 / 64bit
Eclipse 4.2 Juno (日本語パッチ済)

スポンサーサイト
最新トラックバック
検索フォーム
ブロとも申請フォーム
QRコード
QR
Twitter
2013/01/04 19:00 カウント開始

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。