http://blog.csdn.net/cping1982/archive/2009/10/16/4683949.aspx

这几天开着代理研究android(主要是长期以来 developer.android.com 被墙撞……),总算初步掌握了android的图形处理方式,准备在Blog上写一些经验性的总结。


一、Android Virtual Device仿真界面对应快捷


view plaincopy to clipboardprint?
模拟项 设备键 PC键
Home HOME
Menu (left softkey) F2 or Page-up button
Star (right softkey) Shift-F2 or Page Down
Back ESC
Call/dial button F3
Hangup/end call button F4
Search F5
Power button F7
Audio volume up button KEYPAD_PLUS, Ctrl-5
Audio volume down button KEYPAD_MINUS, Ctrl-F6
Camera button Ctrl-KEYPAD_5, Ctrl-F3
Switch to previous layout orientation (for example, portrait, landscape) KEYPAD_7, F11
Switch to next layout orientation (for example, portrait, landscape) KEYPAD_9, F12
Toggle cell networking on/off F8
Toggle code profiling F9 (only with -trace startup option)
Toggle fullscreen mode Alt-Enter
Toggle trackball mode F6
Enter trackball mode temporarily (while key is pressed) Delete
DPad left/up/right/down KEYPAD_4/8/6/2
DPad center click KEYPAD_5
Onion alpha increase/decrease KEYPAD_MULTIPLY(*) / KEYPAD_DIVIDE(/)
模拟项 设备键 PC键
Home HOME
Menu (left softkey) F2 or Page-up button
Star (right softkey) Shift-F2 or Page Down
Back ESC
Call/dial button F3
Hangup/end call button F4
Search F5
Power button F7
Audio volume up button KEYPAD_PLUS, Ctrl-5
Audio volume down button KEYPAD_MINUS, Ctrl-F6
Camera button Ctrl-KEYPAD_5, Ctrl-F3
Switch to previous layout orientation (for example, portrait, landscape) KEYPAD_7, F11
Switch to next layout orientation (for example, portrait, landscape) KEYPAD_9, F12
Toggle cell networking on/off F8
Toggle code profiling F9 (only with -trace startup option)
Toggle fullscreen mode Alt-Enter
Toggle trackball mode F6
Enter trackball mode temporarily (while key is pressed) Delete
DPad left/up/right/down KEYPAD_4/8/6/2
DPad center click KEYPAD_5
Onion alpha increase/decrease KEYPAD_MULTIPLY(*) / KEYPAD_DIVIDE(/)


二、要想在View中绘制图形,至少需要用到以下三者

1、Bitmap

Android中使用Bitmap承载图像资源,其默认支持4种图像格式(调用方式,Bitmap.Config.XXXX),分别为ALPHA8、RGB565、ARGB4444、ARGB8888,单就显示效果而言以ARGB8888效果最佳,ALPHA8效果最差,当然占用资源与之相反。

不过Bitmap本身的运算量非常小,其具体操作大量依赖于native,如下所示:

view plaincopy to clipboardprint?
private static native Bitmap nativeCreate(int[] colors, int offset,
int stride, int width, int height,
int nativeConfig, boolean mutable);
private static native Bitmap nativeCopy(int srcBitmap, int nativeConfig,
boolean isMutable);
private static native void nativeDestructor(int nativeBitmap);
private static native void nativeRecycle(int nativeBitmap);
private static native boolean nativeCompress(int nativeBitmap, int format,
int quality, OutputStream stream,
byte[] tempStorage);
private static native void nativeErase(int nativeBitmap, int color);
private static native int nativeWidth(int nativeBitmap);
private static native int nativeHeight(int nativeBitmap);
private static native int nativeRowBytes(int nativeBitmap);
private static native int nativeConfig(int nativeBitmap);
private static native boolean nativeHasAlpha(int nativeBitmap);

private static native int nativeGetPixel(int nativeBitmap, int x, int y);
private static native void nativeGetPixels(int nativeBitmap, int[] pixels,
int offset, int stride, int x,
int y, int width, int height);

private static native void nativeSetPixel(int nativeBitmap, int x, int y,
int color);
private static native void nativeSetPixels(int nativeBitmap, int[] colors,
int offset, int stride, int x,
int y, int width, int height);
private static native void nativeCopyPixelsToBuffer(int nativeBitmap,
Buffer dst);
private static native void nativeCopyPixelsFromBuffer(int nb, Buffer src);
private static native Bitmap nativeCreateFromParcel(Parcel p);
// returns true on success
private static native boolean nativeWriteToParcel(int nativeBitmap,
boolean isMutable,
Parcel p);
// returns a new bitmap built from the native bitmap's alpha, and the paint
private static native Bitmap nativeExtractAlpha(int nativeBitmap,
int nativePaint,
int[] offsetXY);
private static native Bitmap nativeCreate(int[] colors, int offset,
int stride, int width, int height,
int nativeConfig, boolean mutable);
private static native Bitmap nativeCopy(int srcBitmap, int nativeConfig,
boolean isMutable);
private static native void nativeDestructor(int nativeBitmap);
private static native void nativeRecycle(int nativeBitmap);
private static native boolean nativeCompress(int nativeBitmap, int format,
int quality, OutputStream stream,
byte[] tempStorage);
private static native void nativeErase(int nativeBitmap, int color);
private static native int nativeWidth(int nativeBitmap);
private static native int nativeHeight(int nativeBitmap);
private static native int nativeRowBytes(int nativeBitmap);
private static native int nativeConfig(int nativeBitmap);
private static native boolean nativeHasAlpha(int nativeBitmap);

private static native int nativeGetPixel(int nativeBitmap, int x, int y);
private static native void nativeGetPixels(int nativeBitmap, int[] pixels,
int offset, int stride, int x,
int y, int width, int height);

private static native void nativeSetPixel(int nativeBitmap, int x, int y,
int color);
private static native void nativeSetPixels(int nativeBitmap, int[] colors,
int offset, int stride, int x,
int y, int width, int height);
private static native void nativeCopyPixelsToBuffer(int nativeBitmap,
Buffer dst);
private static native void nativeCopyPixelsFromBuffer(int nb, Buffer src);
private static native Bitmap nativeCreateFromParcel(Parcel p);
// returns true on success
private static native boolean nativeWriteToParcel(int nativeBitmap,
boolean isMutable,
Parcel p);
// returns a new bitmap built from the native bitmap's alpha, and the paint
private static native Bitmap nativeExtractAlpha(int nativeBitmap,
int nativePaint,
int[] offsetXY);

2、Canvas

Android中使用Canvas对应标准Java应用中的Graphics,其具体操作与Graphics类似,但实际功能却较Graphics为少,需要同Paint配合使用。

与Bitmap近似,Canvas主要实现依赖于OpenGL ES,其本身的运算量非常之小,Canvas本地接口如下所示:


view plaincopy to clipboardprint?
private static native int initRaster(int nativeBitmapOrZero);
private static native int initGL();
private static native void native_setBitmap(int nativeCanvas, int bitmap);
private static native void nativeSetViewport(int nCanvas, int w, int h);
private static native int native_saveLayer(int nativeCanvas, RectF bounds,
int paint, int layerFlags);
private static native int native_saveLayer(int nativeCanvas, float l,
float t, float r, float b,
int paint, int layerFlags);
private static native int native_saveLayerAlpha(int nativeCanvas,
RectF bounds, int alpha,
int layerFlags);
private static native int native_saveLayerAlpha(int nativeCanvas, float l,
float t, float r, float b,
int alpha, int layerFlags);
private static native void native_concat(int nCanvas, int nMatrix);
private static native void native_setMatrix(int nCanvas, int nMatrix);
private static native boolean native_clipRect(int nCanvas,
float left, float top,
float right, float bottom,
int regionOp);
private static native boolean native_clipPath(int nativeCanvas,
int nativePath,
int regionOp);
private static native boolean native_clipRegion(int nativeCanvas,
int nativeRegion,
int regionOp);
private static native void nativeSetDrawFilter(int nativeCanvas,
int nativeFilter);
private static native boolean native_getClipBounds(int nativeCanvas,
Rect bounds);
private static native void native_getCTM(int canvas, int matrix);
private static native boolean native_quickReject(int nativeCanvas,
RectF rect,
int native_edgeType);
private static native boolean native_quickReject(int nativeCanvas,
int path,
int native_edgeType);
private static native boolean native_quickReject(int nativeCanvas,
float left, float top,
float right, float bottom,
int native_edgeType);
private static native void native_drawRGB(int nativeCanvas, int r, int g,
int b);
private static native void native_drawARGB(int nativeCanvas, int a, int r,
int g, int b);
private static native void native_drawColor(int nativeCanvas, int color);
private static native void native_drawColor(int nativeCanvas, int color,
int mode);
private static native void native_drawPaint(int nativeCanvas, int paint);
private static native void native_drawLine(int nativeCanvas, float startX,
float startY, float stopX,
float stopY, int paint);
private static native void native_drawRect(int nativeCanvas, RectF rect,
int paint);
private static native void native_drawRect(int nativeCanvas, float left,
float top, float right,
float bottom, int paint);
private static native void native_drawOval(int nativeCanvas, RectF oval,
int paint);
private static native void native_drawCircle(int nativeCanvas, float cx,
float cy, float radius,
int paint);
private static native void native_drawArc(int nativeCanvas, RectF oval,
float startAngle, float sweep,
boolean useCenter, int paint);
private static native void native_drawRoundRect(int nativeCanvas,
RectF rect, float rx,
float ry, int paint);
private static native void native_drawPath(int nativeCanvas, int path,
int paint);
private native void native_drawBitmap(int nativeCanvas, int bitmap,
float left, float top,
int nativePaintOrZero, boolean autoScale,
float densityScale);
private native void native_drawBitmap(int nativeCanvas, int bitmap,
Rect src, RectF dst,
int nativePaintOrZero);
private static native void native_drawBitmap(int nativeCanvas, int bitmap,
Rect src, Rect dst,
int nativePaintOrZero);
private static native void native_drawBitmap(int nativeCanvas, int[] colors,
int offset, int stride, float x,
float y, int width, int height,
boolean hasAlpha,
int nativePaintOrZero);
private static native void nativeDrawBitmapMatrix(int nCanvas, int nBitmap,
int nMatrix, int nPaint);
private static native void nativeDrawBitmapMesh(int nCanvas, int nBitmap,
int meshWidth, int meshHeight,
float[] verts, int vertOffset,
int[] colors, int colorOffset, int nPaint);
private static native void nativeDrawVertices(int nCanvas, int mode, int n,
float[] verts, int vertOffset, float[] texs, int texOffset,
int[] colors, int colorOffset, short[] indices,
int indexOffset, int indexCount, int nPaint);

private static native void native_drawText(int nativeCanvas, char[] text,
int index, int count, float x,
float y, int paint);
private static native void native_drawText(int nativeCanvas, String text,
int start, int end, float x,
float y, int paint);
private static native void native_drawPosText(int nativeCanvas,
char[] text, int index,
int count, float[] pos,
int paint);
private static native void native_drawPosText(int nativeCanvas,
String text, float[] pos,
int paint);
private static native void native_drawTextOnPath(int nativeCanvas,
char[] text, int index,
int count, int path,
float hOffset,
float vOffset, int paint);
private static native void native_drawTextOnPath(int nativeCanvas,
String text, int path,
float hOffset,
float vOffset, int paint);
private static native void native_drawPicture(int nativeCanvas,
int nativePicture);
private static native void finalizer(int nativeCanvas);
private static native int initRaster(int nativeBitmapOrZero);
private static native int initGL();
private static native void native_setBitmap(int nativeCanvas, int bitmap);
private static native void nativeSetViewport(int nCanvas, int w, int h);
private static native int native_saveLayer(int nativeCanvas, RectF bounds,
int paint, int layerFlags);
private static native int native_saveLayer(int nativeCanvas, float l,
float t, float r, float b,
int paint, int layerFlags);
private static native int native_saveLayerAlpha(int nativeCanvas,
RectF bounds, int alpha,
int layerFlags);
private static native int native_saveLayerAlpha(int nativeCanvas, float l,
float t, float r, float b,
int alpha, int layerFlags);
private static native void native_concat(int nCanvas, int nMatrix);
private static native void native_setMatrix(int nCanvas, int nMatrix);
private static native boolean native_clipRect(int nCanvas,
float left, float top,
float right, float bottom,
int regionOp);
private static native boolean native_clipPath(int nativeCanvas,
int nativePath,
int regionOp);
private static native boolean native_clipRegion(int nativeCanvas,
int nativeRegion,
int regionOp);
private static native void nativeSetDrawFilter(int nativeCanvas,
int nativeFilter);
private static native boolean native_getClipBounds(int nativeCanvas,
Rect bounds);
private static native void native_getCTM(int canvas, int matrix);
private static native boolean native_quickReject(int nativeCanvas,
RectF rect,
int native_edgeType);
private static native boolean native_quickReject(int nativeCanvas,
int path,
int native_edgeType);
private static native boolean native_quickReject(int nativeCanvas,
float left, float top,
float right, float bottom,
int native_edgeType);
private static native void native_drawRGB(int nativeCanvas, int r, int g,
int b);
private static native void native_drawARGB(int nativeCanvas, int a, int r,
int g, int b);
private static native void native_drawColor(int nativeCanvas, int color);
private static native void native_drawColor(int nativeCanvas, int color,
int mode);
private static native void native_drawPaint(int nativeCanvas, int paint);
private static native void native_drawLine(int nativeCanvas, float startX,
float startY, float stopX,
float stopY, int paint);
private static native void native_drawRect(int nativeCanvas, RectF rect,
int paint);
private static native void native_drawRect(int nativeCanvas, float left,
float top, float right,
float bottom, int paint);
private static native void native_drawOval(int nativeCanvas, RectF oval,
int paint);
private static native void native_drawCircle(int nativeCanvas, float cx,
float cy, float radius,
int paint);
private static native void native_drawArc(int nativeCanvas, RectF oval,
float startAngle, float sweep,
boolean useCenter, int paint);
private static native void native_drawRoundRect(int nativeCanvas,
RectF rect, float rx,
float ry, int paint);
private static native void native_drawPath(int nativeCanvas, int path,
int paint);
private native void native_drawBitmap(int nativeCanvas, int bitmap,
float left, float top,
int nativePaintOrZero, boolean autoScale,
float densityScale);
private native void native_drawBitmap(int nativeCanvas, int bitmap,
Rect src, RectF dst,
int nativePaintOrZero);
private static native void native_drawBitmap(int nativeCanvas, int bitmap,
Rect src, Rect dst,
int nativePaintOrZero);
private static native void native_drawBitmap(int nativeCanvas, int[] colors,
int offset, int stride, float x,
float y, int width, int height,
boolean hasAlpha,
int nativePaintOrZero);
private static native void nativeDrawBitmapMatrix(int nCanvas, int nBitmap,
int nMatrix, int nPaint);
private static native void nativeDrawBitmapMesh(int nCanvas, int nBitmap,
int meshWidth, int meshHeight,
float[] verts, int vertOffset,
int[] colors, int colorOffset, int nPaint);
private static native void nativeDrawVertices(int nCanvas, int mode, int n,
float[] verts, int vertOffset, float[] texs, int texOffset,
int[] colors, int colorOffset, short[] indices,
int indexOffset, int indexCount, int nPaint);

private static native void native_drawText(int nativeCanvas, char[] text,
int index, int count, float x,
float y, int paint);
private static native void native_drawText(int nativeCanvas, String text,
int start, int end, float x,
float y, int paint);
private static native void native_drawPosText(int nativeCanvas,
char[] text, int index,
int count, float[] pos,
int paint);
private static native void native_drawPosText(int nativeCanvas,
String text, float[] pos,
int paint);
private static native void native_drawTextOnPath(int nativeCanvas,
char[] text, int index,
int count, int path,
float hOffset,
float vOffset, int paint);
private static native void native_drawTextOnPath(int nativeCanvas,
String text, int path,
float hOffset,
float vOffset, int paint);
private static native void native_drawPicture(int nativeCanvas,
int nativePicture);
private static native void finalizer(int nativeCanvas);

3、Paint

用以设定图像的绘制方式,可以同Canvas一道看作Graphics功能的拆分,只有当Canvas与Paint共同使用时,才可能实现Graphics的大部分功能(并非全部)。

Paint依旧大量依赖于本地接口,具体函数如下:

view plaincopy to clipboardprint?
private static native int native_init();
private static native int native_initWithPaint(int paint);
private static native void native_reset(int native_object);
private static native void native_set(int native_dst, int native_src);
private static native int native_getStyle(int native_object);
private static native void native_setStyle(int native_object, int style);
private static native int native_getStrokeCap(int native_object);
private static native void native_setStrokeCap(int native_object, int cap);
private static native int native_getStrokeJoin(int native_object);
private static native void native_setStrokeJoin(int native_object,
int join);
private static native boolean native_getFillPath(int native_object,
int src, int dst);
private static native int native_setShader(int native_object, int shader);
private static native int native_setColorFilter(int native_object,
int filter);
private static native int native_setXfermode(int native_object,
int xfermode);
private static native int native_setPathEffect(int native_object,
int effect);
private static native int native_setMaskFilter(int native_object,
int maskfilter);
private static native int native_setTypeface(int native_object,
int typeface);
private static native int native_setRasterizer(int native_object,
int rasterizer);
private static native int native_getTextAlign(int native_object);
private static native void native_setTextAlign(int native_object,
int align);
private static native float native_getFontMetrics(int native_paint,
FontMetrics metrics);
private static native int native_getTextWidths(int native_object,
char[] text, int index, int count, float[] widths);
private static native int native_getTextWidths(int native_object,
String text, int start, int end, float[] widths);
private static native void native_getTextPath(int native_object,
char[] text, int index, int count, float x, float y, int path);
private static native void native_getTextPath(int native_object,
String text, int start, int end, float x, float y, int path);
private static native void nativeGetStringBounds(int nativePaint,
String text, int start, int end, Rect bounds);
private static native void nativeGetCharArrayBounds(int nativePaint,
char[] text, int index, int count, Rect bounds);
private static native void finalizer(int nativePaint);
private static native int native_init();
private static native int native_initWithPaint(int paint);
private static native void native_reset(int native_object);
private static native void native_set(int native_dst, int native_src);
private static native int native_getStyle(int native_object);
private static native void native_setStyle(int native_object, int style);
private static native int native_getStrokeCap(int native_object);
private static native void native_setStrokeCap(int native_object, int cap);
private static native int native_getStrokeJoin(int native_object);
private static native void native_setStrokeJoin(int native_object,
int join);
private static native boolean native_getFillPath(int native_object,
int src, int dst);
private static native int native_setShader(int native_object, int shader);
private static native int native_setColorFilter(int native_object,
int filter);
private static native int native_setXfermode(int native_object,
int xfermode);
private static native int native_setPathEffect(int native_object,
int effect);
private static native int native_setMaskFilter(int native_object,
int maskfilter);
private static native int native_setTypeface(int native_object,
int typeface);
private static native int native_setRasterizer(int native_object,
int rasterizer);
private static native int native_getTextAlign(int native_object);
private static native void native_setTextAlign(int native_object,
int align);
private static native float native_getFontMetrics(int native_paint,
FontMetrics metrics);
private static native int native_getTextWidths(int native_object,
char[] text, int index, int count, float[] widths);
private static native int native_getTextWidths(int native_object,
String text, int start, int end, float[] widths);
private static native void native_getTextPath(int native_object,
char[] text, int index, int count, float x, float y, int path);
private static native void native_getTextPath(int native_object,
String text, int start, int end, float x, float y, int path);
private static native void nativeGetStringBounds(int nativePaint,
String text, int start, int end, Rect bounds);
private static native void nativeGetCharArrayBounds(int nativePaint,
char[] text, int index, int count, Rect bounds);
private static native void finalizer(int nativePaint);


Android绘图的基本示例: canvas.drawBitmap(bitmap, 0, 0, paint) // canvas代表画布 bitmap作为图像资源 paint决定绘图方式

3、Android的窗口构成,即Activity + View = Form。

Android以Activity类作为窗体容器,以View(或SurfaceView等)绘制所有的按钮及界面,以AndroidManifest.xml配置相关的初始化资源,Android图形应用的一切通过它们衍生开来。

由于Android的线程安全机制并不等同于标准Java应用,invalidate()不能循环绘制View(偶实际试验了,丢到Thread里就死|||),所以View的图形绘制需要通过Handler处理,它将在函数内实现了一个类似于递归的循环线程,结构如下(具体实现请见Android提供的snake示例):

sendMessageDelayed->handleMessage->handleMessage 再次呼叫 sendMessageDelayed->handleMessage 被呼叫->循环

这种线程结构虽然简单且高效,但是很多常见的线程手段却无法在其中实现,因此只适合简单的应用(比如计时器,定时绘图等),复杂的线程结构则需要SurfaceView。

SurfaceView是View的子类,它继承自View。与只能使用Handler方式循环绘制图像的View不同,SurfaceView通过调用一对lockCanvas()和unlockCanvasAndPost()进行绘图,具体实现可见Google提供的LunarLander示例。

根据鄙人实测,View的Handler方式较SurfaceView的lockCanvas()与unlockCanvasAndPost()方式FPS为高,惟独可控性太差,本人推荐在简单应用使用View,在复杂应用使用SurfaceView。

另外xml中屏幕纵、横核定项如下:

screenOrientation="portrait" 纵向屏幕

screenOrientation="landscape" 横向屏幕

与之对应的代码设定方式是在Activity中setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)与setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)

PS:Android中所有图形设备都基于OpenGL ES,默认存在Z-Buffer,绝对不会出现Java桌面应用中的闪烁问题,算是一项进步。

下面我给出一个简单的Android绘图示例,也是LGame-Simple在Android中的最初原型代码,我们可以看到Android与标准Java桌面应用的差异实际上是极为细微的。


源码下载地址:http://code.google.com/p/loon-simple/downloads/list


PS:此用例中所有[LA]开头Java文件为Android下专用,否则皆为LGame-Simple通用。

LAGameView.java(对应LGame-Simple中的GameView)

view plaincopy to clipboardprint?
package org.loon.framework.android.game;
import system.images.LAGraphicsUtils;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
*
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email <a title="" href="http://hi.baidu.com/ceponline" mce_href="http://hi.baidu.com/ceponline" target="_blank">ceponline</a>@yahoo.com.cn
* @version 0.1.0
*/
public class LAGameView extends SurfaceView implements SurfaceHolder.Callback {
// SurfaceView继承自View
private final static long MAX_INTERVAL = 1000L;
final static private int fpsX = 5;
final static private int fpsY = 20;
private transient boolean start, isFPS, running;
private transient int width, height;
private transient long maxFrames, curTime, startTime, offsetTime, curFPS,
calcInterval;
private transient double frameCount;
private SurfaceHolder surfaceHolder;
private CanvasThread mainLoop;
private LAImage screen;
private LAGraphics canvasGraphics;
private LAHandler handler;
private Rect rect;
public LAGameView(Activity activity) {
this(activity, false);
}
public LAGameView(Activity activity, boolean isLandscape) {
super(activity.getApplicationContext());
LASystem.gc();
LASystem.setupHandler(activity, this);
this.handler = LASystem.getSystemHandler();
this.handler.setLandscape(isLandscape);
this.setOnCreateContextMenuListener(handler);
this.setOnClickListener(handler);
this.setOnFocusChangeListener(handler);
this.setOnKeyListener(handler);
this.setOnLongClickListener(handler);
this.setOnTouchListener(handler);
this.screen = new LAImage(width = handler.getWidth(), height = handler
.getHeight());
this.rect = new Rect(0, 0, width, height);
System.out.println("width=" + width + ",height=" + height);
this.mainLoop = new CanvasThread();
this.surfaceHolder = getHolder();
this.surfaceHolder.addCallback(this);
this.surfaceHolder.setSizeFromLayout();
this.setRunning(true);
this.setFPS(LASystem.DEFAULT_MAX_FPS);
this.canvasGraphics = screen.getLAGraphics();
this.setFocusable(true);
this.setFocusableInTouchMode(true);
this.requestFocus();
handler.getActivity().setContentView(this);
}
public void setScreen(ILAScreen screen) {
this.handler.setScreen(screen);
}
public void destroy() {
if (mainLoop != null) {
mainLoop = null;
}
LAGraphicsUtils.destroyImages();
LASystem.gc();
}
class CanvasThread extends Thread {
public void run() {
final LTimerContext timerContext = new LTimerContext();
timerContext.setTimeMillis(startTime = System.currentTimeMillis());
ILAScreen iscreen = null;
Canvas canvas = null;
do {
if (!start) {
continue;
}
iscreen = handler.getScreen();
canvasGraphics.drawClear();
iscreen.createUI(canvasGraphics);
curTime = System.currentTimeMillis();
timerContext.setTimeSinceLastUpdate(curTime
- timerContext.getTimeMillis());
timerContext.setSleepTimeMillis((offsetTime - timerContext
.getTimeSinceLastUpdate())
- timerContext.getOverSleepTimeMillis());
if (timerContext.getSleepTimeMillis() > 0) {
try {
Thread.sleep(timerContext.getSleepTimeMillis());
} catch (InterruptedException e) {
}
timerContext.setOverSleepTimeMillis((System
.currentTimeMillis() - curTime)
- timerContext.getSleepTimeMillis());
} else {
timerContext.setOverSleepTimeMillis(0L);
}
timerContext.setTimeMillis(System.currentTimeMillis());
iscreen.runTimer(timerContext);
if (isFPS) {
tickFrames();
canvasGraphics.setColor(Color.WHITE);
canvasGraphics.setAntiAlias(true);
canvasGraphics.drawString(("FPS:" + curFPS).intern(), fpsX,
fpsY);
canvasGraphics.setAntiAlias(false);
}
try {
canvas = surfaceHolder.lockCanvas(rect);
synchronized (surfaceHolder) {
canvas.drawBitmap(screen.getBitmap(), 0, 0, null);
}
} finally {
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
if (isFocusable()) {
continue;
}
try {
Thread.sleep(30);
} catch (InterruptedException e) {
}
LASystem.gc(10000, 1);
} while (running);
destroy();
}
private void tickFrames() {
frameCount++;
calcInterval += offsetTime;
if (calcInterval >= MAX_INTERVAL) {
long timeNow = System.currentTimeMillis();
long realElapsedTime = timeNow - startTime;
curFPS = (long) ((frameCount / realElapsedTime) * MAX_INTERVAL);
frameCount = 0L;
calcInterval = 0L;
startTime = timeNow;
}
}
}
public Thread getMainLoop() {
return mainLoop;
}
public void mainLoop() {
this.startPaint();
}
public void mainStop() {
this.endPaint();
}
public void startPaint() {
this.start = true;
}
public void endPaint() {
this.start = false;
}
public void setFPS(long frames) {
this.maxFrames = frames;
this.offsetTime = (long) (1.0 / maxFrames * MAX_INTERVAL);
}
public long getMaxFPS() {
return this.maxFrames;
}
public long getCurrentFPS() {
return this.curFPS;
}
public void setShowFPS(boolean isFPS) {
this.isFPS = isFPS;
}
public boolean isRunning() {
return running;
}
public void setRunning(boolean running) {
this.running = running;
}
public LAHandler getLHandler() {
return handler;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
holder.setFixedSize(width, height);
}
public void surfaceCreated(SurfaceHolder holder) {
mainLoop.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean result = true;
setRunning(false);
while (result) {
try {
mainLoop.join();
result = false;
} catch (InterruptedException e) {
}
}
mainLoop = null;
}
}
package org.loon.framework.android.game;
import system.images.LAGraphicsUtils;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
*
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email <a title="" href="http://hi.baidu.com/ceponline" mce_href="http://hi.baidu.com/ceponline" target="_blank">ceponline</a>@yahoo.com.cn
* @version 0.1.0
*/
public class LAGameView extends SurfaceView implements SurfaceHolder.Callback {
// SurfaceView继承自View
private final static long MAX_INTERVAL = 1000L;
final static private int fpsX = 5;
final static private int fpsY = 20;
private transient boolean start, isFPS, running;
private transient int width, height;
private transient long maxFrames, curTime, startTime, offsetTime, curFPS,
calcInterval;
private transient double frameCount;
private SurfaceHolder surfaceHolder;
private CanvasThread mainLoop;
private LAImage screen;
private LAGraphics canvasGraphics;
private LAHandler handler;
private Rect rect;
public LAGameView(Activity activity) {
this(activity, false);
}
public LAGameView(Activity activity, boolean isLandscape) {
super(activity.getApplicationContext());
LASystem.gc();
LASystem.setupHandler(activity, this);
this.handler = LASystem.getSystemHandler();
this.handler.setLandscape(isLandscape);
this.setOnCreateContextMenuListener(handler);
this.setOnClickListener(handler);
this.setOnFocusChangeListener(handler);
this.setOnKeyListener(handler);
this.setOnLongClickListener(handler);
this.setOnTouchListener(handler);
this.screen = new LAImage(width = handler.getWidth(), height = handler
.getHeight());
this.rect = new Rect(0, 0, width, height);
System.out.println("width=" + width + ",height=" + height);
this.mainLoop = new CanvasThread();
this.surfaceHolder = getHolder();
this.surfaceHolder.addCallback(this);
this.surfaceHolder.setSizeFromLayout();
this.setRunning(true);
this.setFPS(LASystem.DEFAULT_MAX_FPS);
this.canvasGraphics = screen.getLAGraphics();
this.setFocusable(true);
this.setFocusableInTouchMode(true);
this.requestFocus();
handler.getActivity().setContentView(this);
}
public void setScreen(ILAScreen screen) {
this.handler.setScreen(screen);
}
public void destroy() {
if (mainLoop != null) {
mainLoop = null;
}
LAGraphicsUtils.destroyImages();
LASystem.gc();
}
class CanvasThread extends Thread {
public void run() {
final LTimerContext timerContext = new LTimerContext();
timerContext.setTimeMillis(startTime = System.currentTimeMillis());
ILAScreen iscreen = null;
Canvas canvas = null;
do {
if (!start) {
continue;
}
iscreen = handler.getScreen();
canvasGraphics.drawClear();
iscreen.createUI(canvasGraphics);
curTime = System.currentTimeMillis();
timerContext.setTimeSinceLastUpdate(curTime
- timerContext.getTimeMillis());
timerContext.setSleepTimeMillis((offsetTime - timerContext
.getTimeSinceLastUpdate())
- timerContext.getOverSleepTimeMillis());
if (timerContext.getSleepTimeMillis() > 0) {
try {
Thread.sleep(timerContext.getSleepTimeMillis());
} catch (InterruptedException e) {
}
timerContext.setOverSleepTimeMillis((System
.currentTimeMillis() - curTime)
- timerContext.getSleepTimeMillis());
} else {
timerContext.setOverSleepTimeMillis(0L);
}
timerContext.setTimeMillis(System.currentTimeMillis());
iscreen.runTimer(timerContext);
if (isFPS) {
tickFrames();
canvasGraphics.setColor(Color.WHITE);
canvasGraphics.setAntiAlias(true);
canvasGraphics.drawString(("FPS:" + curFPS).intern(), fpsX,
fpsY);
canvasGraphics.setAntiAlias(false);
}
try {
canvas = surfaceHolder.lockCanvas(rect);
synchronized (surfaceHolder) {
canvas.drawBitmap(screen.getBitmap(), 0, 0, null);
}
} finally {
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
if (isFocusable()) {
continue;
}
try {
Thread.sleep(30);
} catch (InterruptedException e) {
}
LASystem.gc(10000, 1);
} while (running);
destroy();
}
private void tickFrames() {
frameCount++;
calcInterval += offsetTime;
if (calcInterval >= MAX_INTERVAL) {
long timeNow = System.currentTimeMillis();
long realElapsedTime = timeNow - startTime;
curFPS = (long) ((frameCount / realElapsedTime) * MAX_INTERVAL);
frameCount = 0L;
calcInterval = 0L;
startTime = timeNow;
}
}
}
public Thread getMainLoop() {
return mainLoop;
}
public void mainLoop() {
this.startPaint();
}
public void mainStop() {
this.endPaint();
}
public void startPaint() {
this.start = true;
}
public void endPaint() {
this.start = false;
}
public void setFPS(long frames) {
this.maxFrames = frames;
this.offsetTime = (long) (1.0 / maxFrames * MAX_INTERVAL);
}
public long getMaxFPS() {
return this.maxFrames;
}
public long getCurrentFPS() {
return this.curFPS;
}
public void setShowFPS(boolean isFPS) {
this.isFPS = isFPS;
}
public boolean isRunning() {
return running;
}
public void setRunning(boolean running) {
this.running = running;
}
public LAHandler getLHandler() {
return handler;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
holder.setFixedSize(width, height);
}
public void surfaceCreated(SurfaceHolder holder) {
mainLoop.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean result = true;
setRunning(false);
while (result) {
try {
mainLoop.join();
result = false;
} catch (InterruptedException e) {
}
}
mainLoop = null;
}
}

LAScreen.java(对应LGame-Simple中的Screen)

view plaincopy to clipboardprint?
package org.loon.framework.android.game;
import system.images.LAGraphicsUtils;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
/**
*
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email <a title="" href="http://hi.baidu.com/ceponline" mce_href="http://hi.baidu.com/ceponline" target="_blank">ceponline</a>@yahoo.com.cn
* @version 0.1.0
*/
public abstract class LAScreen implements ILAScreen {
private ILAHandler handler;
private int width, height;
public LAScreen() {
this.handler = LASystem.getSystemHandler();
this.width = handler.getWidth();
this.height = handler.getHeight();
}
public LAImage getLAImage(String fileName){
return LAGraphicsUtils.loadLAImage(fileName);
}

public synchronized void createUI(LAGraphics g) {
draw(g);
}
public abstract void draw(LAGraphics g);
public synchronized void runTimer(LTimerContext timer) {
alter(timer);
}
public abstract void alter(LTimerContext timer);
public void setScreen(ILAScreen screen) {
this.handler.setScreen(screen);
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public abstract boolean onKey(int keyCode, KeyEvent e);
public boolean onKey(View v, int keyCode, KeyEvent event) {
return onKey(keyCode, event);
}
public abstract void onFocusChange(boolean hasFocus);
public void onFocusChange(View v, boolean hasFocus) {
onFocusChange(hasFocus);
}
public abstract boolean onLongClick();
public boolean onLongClick(View v) {
return onLongClick();
}
public abstract boolean onClick();
public void onClick(View v) {
onClick();
}
public abstract void onCreateContextMenu(ContextMenu menu,
ContextMenuInfo menuInfo);
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
onCreateContextMenu(menu, menuInfo);
}
public abstract boolean onTouch(MotionEvent e);
public boolean onTouch(View v, MotionEvent event) {
return onTouch(event);
}
}
package org.loon.framework.android.game;
import system.images.LAGraphicsUtils;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
/**
*
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email <a title="" href="http://hi.baidu.com/ceponline" mce_href="http://hi.baidu.com/ceponline" target="_blank">ceponline</a>@yahoo.com.cn
* @version 0.1.0
*/
public abstract class LAScreen implements ILAScreen {
private ILAHandler handler;
private int width, height;
public LAScreen() {
this.handler = LASystem.getSystemHandler();
this.width = handler.getWidth();
this.height = handler.getHeight();
}
public LAImage getLAImage(String fileName){
return LAGraphicsUtils.loadLAImage(fileName);
}

public synchronized void createUI(LAGraphics g) {
draw(g);
}
public abstract void draw(LAGraphics g);
public synchronized void runTimer(LTimerContext timer) {
alter(timer);
}
public abstract void alter(LTimerContext timer);
public void setScreen(ILAScreen screen) {
this.handler.setScreen(screen);
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public abstract boolean onKey(int keyCode, KeyEvent e);
public boolean onKey(View v, int keyCode, KeyEvent event) {
return onKey(keyCode, event);
}
public abstract void onFocusChange(boolean hasFocus);
public void onFocusChange(View v, boolean hasFocus) {
onFocusChange(hasFocus);
}
public abstract boolean onLongClick();
public boolean onLongClick(View v) {
return onLongClick();
}
public abstract boolean onClick();
public void onClick(View v) {
onClick();
}
public abstract void onCreateContextMenu(ContextMenu menu,
ContextMenuInfo menuInfo);
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
onCreateContextMenu(menu, menuInfo);
}
public abstract boolean onTouch(MotionEvent e);
public boolean onTouch(View v, MotionEvent event) {
return onTouch(event);
}
}


Main.java(启动类)

view plaincopy to clipboardprint?
package org.loon.framework.android.game;
import android.app.Activity;
import android.os.Bundle;
/**
*
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email <a title="" href="http://hi.baidu.com/ceponline" mce_href="http://hi.baidu.com/ceponline" target="_blank">ceponline</a>@yahoo.com.cn
* @version 0.1.0
*/
public class Main extends Activity {
private LAGameView view;
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
view = new LAGameView(this);
view.setScreen(new ScreenTest());
view.setShowFPS(true);
view.mainLoop();
}
protected void onPause() {
if (view != null) {
view.setRunning(false);
}
super.onPause();
}
protected void onStop() {
if (view != null) {
view.setRunning(false);
}
super.onStop();
}
}
package org.loon.framework.android.game;
import android.app.Activity;
import android.os.Bundle;
/**
*
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email <a title="" href="http://hi.baidu.com/ceponline" mce_href="http://hi.baidu.com/ceponline" target="_blank">ceponline</a>@yahoo.com.cn
* @version 0.1.0
*/
public class Main extends Activity {
private LAGameView view;
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
view = new LAGameView(this);
view.setScreen(new ScreenTest());
view.setShowFPS(true);
view.mainLoop();
}
protected void onPause() {
if (view != null) {
view.setRunning(false);
}
super.onPause();
}
protected void onStop() {
if (view != null) {
view.setRunning(false);
}
super.onStop();
}
}

ScreenTest.java(测试类)

view plaincopy to clipboardprint?
package org.loon.framework.android.game;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ContextMenu.ContextMenuInfo;
/**
*
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email <a title="" href="http://hi.baidu.com/ceponline" mce_href="http://hi.baidu.com/ceponline" target="_blank">ceponline</a>@yahoo.com.cn
* @version 0.1.0
*/
public class ScreenTest extends LAScreen {
private LAImage image;
private int tx = 0, ty = 0;
public ScreenTest() {
image = getLAImage("image.png");
}
public void alter(LTimerContext timer) {
}
public void draw(LAGraphics g) {
g.drawImage(image, 55, 55);
g.drawString("Touch X=" + ty, 70, 70);
g.drawString("Touch Y=" + tx, 70, 90);
}
public boolean onClick() {
return false;
}
public void onCreateContextMenu(ContextMenu menu, ContextMenuInfo menuInfo) {
}
public void onFocusChange(boolean hasFocus) {
}
/**
* 手机按键(对应键盘)
*/
public boolean onKey(int keyCode, KeyEvent e) {
return false;
}
public boolean onLongClick() {
return false;
}
/**
* 手机触摸屏(对应鼠标)
*/
public boolean onTouch(MotionEvent e) {
this.tx = (int) e.getX();
this.ty = (int) e.getY();
return false;
}
}
package org.loon.framework.android.game;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.ContextMenu.ContextMenuInfo;
/**
*
* Copyright 2008 - 2009
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loonframework
* @author chenpeng
* @email <a title="" href="http://hi.baidu.com/ceponline" mce_href="http://hi.baidu.com/ceponline" target="_blank">ceponline</a>@yahoo.com.cn
* @version 0.1.0
*/
public class ScreenTest extends LAScreen {
private LAImage image;
private int tx = 0, ty = 0;
public ScreenTest() {
image = getLAImage("image.png");
}
public void alter(LTimerContext timer) {
}
public void draw(LAGraphics g) {
g.drawImage(image, 55, 55);
g.drawString("Touch X=" + ty, 70, 70);
g.drawString("Touch Y=" + tx, 70, 90);
}
public boolean onClick() {
return false;
}
public void onCreateContextMenu(ContextMenu menu, ContextMenuInfo menuInfo) {
}
public void onFocusChange(boolean hasFocus) {
}
/**
* 手机按键(对应键盘)
*/
public boolean onKey(int keyCode, KeyEvent e) {
return false;
}
public boolean onLongClick() {
return false;
}
/**
* 手机触摸屏(对应鼠标)
*/
public boolean onTouch(MotionEvent e) {
this.tx = (int) e.getX();
this.ty = (int) e.getY();
return false;
}
}

横屏效果:

纵屏效果:


源码下载地址:http://code.google.com/p/loon-simple/downloads/list

可以看到,此示例虽为LGame-Simple的简写,但最基础的功能已经实现,我们仅需设定一个继承自LAScreen的游戏屏幕,就可以同LGame-Simple中一样,分模块开发游戏,并且随意更换当前游戏模块及更替按键设定了。

实际上如果您愿意,即使偶不出Android版的LGame-Simple,将其自行移植到Android上的难度也绝对比您所想象的要小得多(当然,Android版偶是肯定会出的^.^)

————————————天下大势,分久必合,合久必分—————————————

事实上Android与标准Java应用近乎一致,唯独在多线程方面有些“恶心”,比如View中的invalidate()函数只能在Handler中做类似递归的handleMessage与sleep相互调用,Thread.currentThread().getContextClassLoader()也无法获得jar内部资源,感觉上就像Google要强制你学习它那套samples应用,而不能更改一样。

把LGame-Simple移植到Android上比我想象的要简单,刚刚又试验了一下,除了有关图形接口与线程的部分,其余直接copy过来就可以用,甚至连代码都不必改,所以12月出LGame-Simple的Android版肯定没问题。(事实上,如果偶现在开始什么都不干只写这个的话,大约5天左右就可以搞定……可惜不现实……)

另外偶可能尝试开发一个函数移植器,看看能不能做到PC与Android上的LGame-Simple游戏间自动代码转换,目前看来可行性蛮高的。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cping1982/archive/2009/10/16/4683949.aspx

更多相关文章

  1. Android学习——基础组件
  2. [Android] AsyncTask使用实例---加载网络图片
  3. android 对文件的操作模式
  4. mtk android 配置mcp
  5. Android(安卓)重启应用代码
  6. Android实现再按一次(返回键)实现退出(应用程序)
  7. Android应用程序全屏显示的方法
  8. Android(安卓)Message机制
  9. Android获取应用程序的信息

随机推荐

  1. 金融行业数据防泄漏,需要关注哪些地方?
  2. 字典和json的区别是什么?Python学习
  3. 学Python需要学数据库吗?Python学习教程!
  4. grid对齐方式与基础实战
  5. flex 容器的 flex-flow, justify-content
  6. 作用域、闭包,类与继承
  7. Linux运维入门教程08-01 (Linux软件包的
  8. linux-系统状态命令
  9. CRM系统如何让企业获得精确客户?
  10. k8s 高可用部署