Android的快速像素操作 [英] Android fast pixel operations
问题描述
我试着写一些code,让我画像素阵列到屏幕上。不过,我在320x240像素得到我的ARM Cortex A8 600MHz的非常louzy性能。
瓶颈在哪里是和/或如何解决它有人能解释一下吗?改变高度和宽度几乎有帮助。我注意到,在Java Swing的类似行为。我用下面code:
包com.pixeldraw;
进口的java.util.ArrayList;进口android.app.Activity;
进口android.content.Context;
进口android.graphics.Bitmap;
进口android.graphics.BitmapFactory;
进口android.graphics.Canvas;
进口android.graphics.Color;
进口android.os.Bundle;
进口android.os.Debug;
进口android.view.MotionEvent;
进口android.view.SurfaceHolder;
进口android.view.SurfaceView;
进口android.view.Window;公共类MainActivity延伸活动{
@覆盖
公共无效的onCreate(捆绑savedInstanceState){
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
的setContentView(新面板(本));
Debug.startMethodTracing(pixeldraw);
} @覆盖
保护无效的onDestroy(){
super.onDestroy();
Debug.stopMethodTracing();
} 类面板扩展了SurfaceView实现SurfaceHolder.Callback {
私人TutorialThread _Thread;
私人位图_buffer;
私人的ArrayList< GraphicObject> _graphics =新的ArrayList< GraphicObject>();
私人诠释宽度= 40;
私人诠释高度= 40;
公共面板(上下文的背景下){
超级(上下文);
。getHolder()的addCallback(本);
_Thread =新TutorialThread(getHolder(),这一点);
setFocusable(真);
} @覆盖
公共布尔onTouchEvent(MotionEvent事件){
同步(_thread.getSurfaceHolder()){
如果(event.getAction()== MotionEvent.ACTION_DOWN){
GraphicObject图形=新GraphicObject(BitmapFactory.de codeResource(getResources(),R.drawable.icon));
。graphic.getCoordinates()setX的((int)的event.getX() - graphic.getGraphic()的getWidth()/ 2);
。graphic.getCoordinates()SETY((int)的event.getY() - graphic.getGraphic()的getHeight()/ 2);
_graphics.add(图形);
}
返回true;
}
}
长lastTime = System.currentTimeMillis的();
INT CLOCKS_PER_SEC = 500;
浮timeCnt = 0;
@覆盖
公共无效的onDraw(帆布油画){
canvas.drawColor(Color.BLACK);
宽度=的getWidth()/ 2;
高度=的getHeight()/ 2; 长frameTime的= System.currentTimeMillis的(); //每帧经过的秒几乎总是小于1.0。
浮动elapsedSeconds =(浮点)(frameTime的 - lastTime)/ CLOCKS_PER_SEC; INT颜色[] =新的INT [宽*高]。
为(中间体X = 0; X&下;宽度; X ++){
对于(INT Y = 0; Y<高度; Y ++){
INT R =(INT)(timeCnt / 5 * 255);
INT B = 0;
INT G = 0;
int类型的= 255;
颜色[X + Y *宽=(A<< 24)| (为r&下; 16)| (G<< 8)| b:
}
}
为(中间体X = 0; X小于10; X ++){
为(中间体Y = 0; Y小于10; Y ++){
INT R = 0;
INT B = 255;
INT G = 0;
int类型的= 255;
颜色[(INT)(timeCnt * 32)+ X + Y *宽=(A<< 24)| (为r&下; 16)| (G<< 8)| b:
}
}
_buffer = Bitmap.createBitmap(颜色,宽度,高度,Bitmap.Config.RGB_565);
canvas.drawBitmap(_buffer,0,0,NULL); timeCnt + = elapsedSeconds;
如果(timeCnt→5)timeCnt = 0;
//更新最后一次计数器,这样我们可以用它下架。
lastTime = frameTime的; } @覆盖
公共无效surfaceChanged(SurfaceHolder架,INT格式,诠释的宽度,高度INT){
// TODO自动生成方法存根
} @覆盖
公共无效surfaceCreated(SurfaceHolder持有人){
_thread.setRunning(真);
_thread.start();
} @覆盖
公共无效surfaceDestroyed(SurfaceHolder持有人){
//简单地从示例应用程序LunarLander复制:
//我们要告诉线程关闭和放大器;等待它完成,要不然
//我们返回后,摸表面和爆炸
布尔重试= TRUE;
_thread.setRunning(假);
而(重试){
尝试{
_thread.join();
重试= FALSE;
}赶上(InterruptedException的E){
//我们会一次又一次地尝试...
}
}
}
} 类TutorialThread继承Thread {
私人SurfaceHolder _surfaceHolder;
私人面板_panel;
私人布尔_run = FALSE; 公共TutorialThread(SurfaceHolder surfaceHolder,面板面板){
_surfaceHolder = surfaceHolder;
_panel =面板;
} 公共无效setRunning(布尔运行){
_run =运行;
} 公共SurfaceHolder getSurfaceHolder(){
返回_surfaceHolder;
} @覆盖
公共无效的run(){
帆布℃;
而(_run){
C = NULL;
尝试{
C = _surfaceHolder.lockCanvas(NULL);
同步(_surfaceHolder){
_panel.onDraw(C);
}
} {最后
//在最终做到这一点,这样如果有异常抛出
//上面的过程中,我们不留在表面
//不一致的状态
如果(C!= NULL){
_surfaceHolder.unlockCanvasAndPost(C);
}
}
}
}
} 类GraphicObject {
/ **
*包含图形的坐标。
* /
公共类坐标{
私人INT _x = 100;
私人INT _y = 0; 公众诠释的getX(){
返回_x + _bitmap.getWidth()/ 2;
} 公共无效setX的(int值){
_x =价值 - _bitmap.getWidth()/ 2;
} 公众诠释的getY(){
返回_y + _bitmap.getHeight()/ 2;
} 公共无效塞蒂(int值){
_y =价值 - _bitmap.getHeight()/ 2;
} 公共字符串的toString(){
返回坐标:(+ _x +/+ _y +);
}
} 私人位图_bitmap;
私人坐标_coordinates; 公共GraphicObject(位图位图){
_bitmap =位图;
_coordinates =新坐标();
} 公共位图getGraphic(){
返回_bitmap;
} 公共坐标getCoordinates(){
返回_coordinates;
}
}
}
从我们公司的经验 - 在近乎全屏位图逐像素操作是在Android上非常慢。一个我们对某种自定义动画最慢的操作是使由drawColor(),其正好在做逐像素在屏幕的填充...
的背景上的黑色所以你的情况可能是罪魁祸首就是
canvas.drawColor(Color.BLACK);
不过说实在的 - 做分析,你就会知道。随着分析可以向下钻取的onDraw,看看哪种方法最花费时间。这是我们发现了。
I'm trying to write some code that let me draw an array of pixels to the screen. However I get very louzy performance on my Arm cortex A8 600mhz at 320x240 pixels.
Can someone explain to me where the bottleneck is and/or how to fix it? Changing the height and width barely helps too. I noticed similar behaviour with Swing in Java. I'm using code below:
package com.pixeldraw;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Debug;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new Panel(this));
Debug.startMethodTracing("pixeldraw");
}
@Override
protected void onDestroy() {
super.onDestroy();
Debug.stopMethodTracing();
}
class Panel extends SurfaceView implements SurfaceHolder.Callback {
private TutorialThread _thread;
private Bitmap _buffer;
private ArrayList<GraphicObject> _graphics = new ArrayList<GraphicObject>();
private int width = 40;
private int height = 40;
public Panel(Context context) {
super(context);
getHolder().addCallback(this);
_thread = new TutorialThread(getHolder(), this);
setFocusable(true);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
synchronized (_thread.getSurfaceHolder()) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
GraphicObject graphic = new GraphicObject(BitmapFactory.decodeResource(getResources(), R.drawable.icon));
graphic.getCoordinates().setX((int) event.getX() - graphic.getGraphic().getWidth() / 2);
graphic.getCoordinates().setY((int) event.getY() - graphic.getGraphic().getHeight() / 2);
_graphics.add(graphic);
}
return true;
}
}
long lastTime = System.currentTimeMillis();
int CLOCKS_PER_SEC = 500;
float timeCnt = 0;
@Override
public void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
width = getWidth()/2;
height = getHeight()/2;
long frameTime = System.currentTimeMillis();
// The elapsed seconds per frame will almost always be less than 1.0.
float elapsedSeconds = (float)(frameTime - lastTime) / CLOCKS_PER_SEC;
int colors[] = new int[width*height];
for (int x = 0; x<width ; x++) {
for (int y = 0; y<height ; y++){
int r = (int)(timeCnt/5*255);
int b = 0;
int g = 0;
int a = 255;
colors[x + y * width] = (a << 24) | (r << 16) | (g << 8) | b;
}
}
for (int x = 0; x<10 ; x++) {
for (int y = 0; y<10; y++){
int r = 0;
int b = 255;
int g = 0;
int a = 255;
colors[(int)(timeCnt*32)+x + y * width] = (a << 24) | (r << 16) | (g << 8) | b;
}
}
_buffer = Bitmap.createBitmap(colors, width, height, Bitmap.Config.RGB_565);
canvas.drawBitmap(_buffer, 0, 0, null);
timeCnt += elapsedSeconds;
if (timeCnt > 5) timeCnt = 0;
// Update the last time counter so that we can use it next frame.
lastTime = frameTime;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
_thread.setRunning(true);
_thread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// simply copied from sample application LunarLander:
// we have to tell thread to shut down & wait for it to finish, or else
// it might touch the Surface after we return and explode
boolean retry = true;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
}
class TutorialThread extends Thread {
private SurfaceHolder _surfaceHolder;
private Panel _panel;
private boolean _run = false;
public TutorialThread(SurfaceHolder surfaceHolder, Panel panel) {
_surfaceHolder = surfaceHolder;
_panel = panel;
}
public void setRunning(boolean run) {
_run = run;
}
public SurfaceHolder getSurfaceHolder() {
return _surfaceHolder;
}
@Override
public void run() {
Canvas c;
while (_run) {
c = null;
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
_panel.onDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
class GraphicObject {
/**
* Contains the coordinates of the graphic.
*/
public class Coordinates {
private int _x = 100;
private int _y = 0;
public int getX() {
return _x + _bitmap.getWidth() / 2;
}
public void setX(int value) {
_x = value - _bitmap.getWidth() / 2;
}
public int getY() {
return _y + _bitmap.getHeight() / 2;
}
public void setY(int value) {
_y = value - _bitmap.getHeight() / 2;
}
public String toString() {
return "Coordinates: (" + _x + "/" + _y + ")";
}
}
private Bitmap _bitmap;
private Coordinates _coordinates;
public GraphicObject(Bitmap bitmap) {
_bitmap = bitmap;
_coordinates = new Coordinates();
}
public Bitmap getGraphic() {
return _bitmap;
}
public Coordinates getCoordinates() {
return _coordinates;
}
}
}
From our company experience - pixel-by-pixel operations on near-full-screen bitmaps are extremely slow on android. One of the slowest operations we had on a custom animation of some sort was to make the background black by drawColor() which is exactly doing pixel-by-pixel filling of the screen...
So in your case probably the culprit is
canvas.drawColor(Color.BLACK);
But indeed - do profiling and you will know. With profiling you can drill down onDraw and see which method takes most time. This is how we found out.
这篇关于Android的快速像素操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!