gpt4 book ai didi

android-animation - Android 2D动画绘图:性能不佳

转载 作者:行者123 更新时间:2023-12-01 05:28:31 25 4
gpt4 key购买 nike

我有一个绘制点网格的应用程序(比如说5x5)。要求用户在该网格上画线。如果用户的手指触摸网格中的一个点,则该点将被着色以显示该点是绘制路径的一部分。另外,将在每两个触摸的点之间绘制一条线。

问题-我的性能很差,这导致以下几件事:


该应用程序真的很慢。
event.getAction()中的运动事件的粒度不正确。我的意思是enter code here而不是例如每10像素记录一次移动,而是每100像素记录一次移动。反过来,这将导致应用程序不会重绘用户触摸过的一些点。
有时运动坐标很简单:例如,用户将手指从像素100移动到像素500,读数可能显示100 ... 200 ... 150 ... 140 ... 300 ... 400。由于某些原因,触摸位置在某些情况下会变得混乱。


查看有关应用如何在用户触摸的点上“漏掉”并且不绘制绿色点的示例:



我尝试了几件事:


添加Thread.sleep(100);在else if(event.getAction() == MotionEvent.ACTION_MOVE)内的onTouchEvent(MotionEvent event)上,我读到这可能使CPU有时间赶上所有这些触摸事件-并没有改变
this.destroyDrawingCache()添加到doDraw()的最后(我用它代替了onDraw,正如我所用的一个教程所建议的那样)。我认为这将清除所有似乎正在减慢系统速度的事件/绘图缓存-并没有改变任何事情。


我是Android动画的新手,所以不确定如何进行:


我知道我应该在doDraw()(我的onDraw())和onTouchEvent()中尽可能少地做。
我阅读了一些有关invalidate()的内容,但不确定如何以及何时使用它。如果我理解正确,则每次调用doDraw()时都会重新绘制我的视图。例如,我的网格是静态的-如何避免重绘它?


++++++++++++++++++++++++ ++ 10月7日更新+++++++++++++++++++++

我尝试使用canvas.drawCircle(xPos, yPos, 8, mNodePaint);而不是canvas.drawBitmap(mBitmap, xPos, yPos, null);。我以为如果我不使用实际的位图,那可能会提高性能。事实上-事实并非如此!我有点困惑,这么简单的应用程序如何对设备造成如此沉重的负担。我一定是在做错误的事情。

++++++++++++++++++++++++ ++ 10月12日更新+++++++++++++++++++++

我考虑了@LadyWoodi的建议-我已经从循环中消除了所有变量声明-不管怎么说,这是一个坏习惯,而且我还摆脱了我使用的所有“ System.Out”行,因此可以将应用行为记录到更好地理解为什么我得到如此差劲的表现。我很伤心地说,如果有性能上的变化(我没有实际测量,帧速率变更),它是可以忽略不计。

还有其他想法吗?

++++++++++++++++++++++++ ++ 10月13日更新+++++++++++++++++++++


由于我有一个静态的点网格(请参阅screenShot中的空心黑点/白点),在游戏过程中始终不变,因此我执行了以下操作:


-绘制一次网格。

-使用Bitmap.createBitmap()将图形捕获为位图。

-使用canvas.drawBitmap()绘制静态点网格的位图。

-当我的线程运行时,我检查是否看到了点网格。如果它正在运行,我将不会重新创建静态点网格。我将仅从以前渲染的位图进行渲染。

令人惊讶的是,这并没有改变我的表现!每次重新绘制点网格都不会对应用程序性能产生真正的视觉效果。


我决定在绘图线程中使用canvas = mHolder.lockCanvas(new Rect(50, 50, 150, 150));。只是出于测试目的,看看我是否每次都限制渲染区域,才能获得更好的性能。此DID也无济于事。
然后,我转向Eclipse中的DDMS工具来尝试对应用程序进行配置。结果是canvas.drawPath(path, mPathPaint);(Canvas.native_drawPath)消耗了大约88.5%的CPU时间!


但为什么??!我的路径绘制非常简单,mGraphics包含路径的集合,我要做的就是弄清楚每个路径是否在游戏屏幕的边界内,然后绘制路径:

//draw path user is creating with her finger on screen
for (Path path : mGraphics)
{
//get path values
mPm = new PathMeasure(path, true);

mPm.getPosTan(0f, mStartCoordinates, null);
//System.out.println("aStartCoordinates X:" + aStartCoordinates[0] + " aStartCoordinates Y:" + aStartCoordinates[1]);
mPm.getPosTan(mPm.getLength(), mEndCoordinates, null);
//System.out.println("aEndCoordinates X:" + aEndCoordinates[0] + " aEndCoordinates Y:" + aEndCoordinates[1]);

//coordinates are within game board boundaries
if((mStartCoordinates[0] >= 1 && mStartCoordinates[1] >= 1) && (mEndCoordinates[0] >= 1 && mEndCoordinates[1] >= 1))
{
canvas.drawPath(path, mPathPaint);
}
}


谁能在我的示例中看到任何不良的编程代码行?

++++++++++++++++++++++++ UPDATE 10月14日+++++++++++++++++++++

我已经对我的 doDraw()方法进行了更改。基本上,我要做的是仅在发生更改时才绘制屏幕。在所有其他情况下,我只存储屏幕的缓存位图并进行渲染。请看一下:

    public void doDraw(Canvas canvas) 
{
synchronized (mViewThread.getSurefaceHolder())
{
if(mGraphics.size() > mPathsCount)
{
mPathsCount = mGraphics.size();

//draw path user is creating with her finger on screen
for (Path path : mGraphics)
{
//get path values
mPm = new PathMeasure(path, true);

mPm.getPosTan(0f, mStartCoordinates, null);
//System.out.println("aStartCoordinates X:" + aStartCoordinates[0] + " aStartCoordinates Y:" + aStartCoordinates[1]);
mPm.getPosTan(mPm.getLength(), mEndCoordinates, null);
//System.out.println("aEndCoordinates X:" + aEndCoordinates[0] + " aEndCoordinates Y:" + aEndCoordinates[1]);

//coordinates are within game board boundaries
if((mStartCoordinates[0] >= 1 && mStartCoordinates[1] >= 1) && (mEndCoordinates[0] >= 1 && mEndCoordinates[1] >= 1))
{
canvas.drawPath(path, mPathPaint);
}
}

//nodes that the path goes through, are repainted green
//these nodes are building the drawn pattern
for (ArrayList<PathPoint> nodePattern : mNodesHitPatterns)
{
for (PathPoint nodeHit : nodePattern)
{
canvas.drawBitmap(mDotOK, nodeHit.x - ((mDotOK.getWidth()/2) - (mNodeBitmap.getWidth()/2)), nodeHit.y - ((mDotOK.getHeight()/2) - (mNodeBitmap.getHeight()/2)), null);
}
}

mGameField = Bitmap.createBitmap(mGridNodesCount * mNodeGap, mGridNodesCount * mNodeGap, Bitmap.Config.ARGB_8888);
}
else
{
canvas.drawBitmap(mGameField, 0f, 0f, null);
}


现在要获得结果-只要设备不必渲染任何路径而只需从位图绘制,内容就会非常快速。但是当我不得不使用 canvas.drawPath()性能重新渲染屏幕时,就变得像吗啡上的乌龟一样迟钝了……我拥有的路径越多(最多6条,甚至更多,这没什么!),渲染的速度就越慢。这有多奇怪? -我的路甚至还没有弯曲-全部都是直线,偶有转弯。我的意思是这条线不是很“复杂”。

我在下面添加了更多代码-如果您有任何改进的想法。

提前谢谢了,
D.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~

public class Panel extends SurfaceView implements SurfaceHolder.Callback {

Bitmap mNodeBitmap;
int mNodeBitmapWidthCenter;
int mNodeBitmapHeightCenter;

Bitmap mDotOK;
ViewThread mViewThread;
ArrayList<PathPoint> mPathPoints;

private ArrayList<Path> mGraphics = new ArrayList<Path>(3);
private ArrayList<ArrayList<PathPoint>> mNodesHitPatterns = new ArrayList<ArrayList<PathPoint>>();

private Paint mPathPaint;

Path mPath = new Path();

//private ArrayList<Point> mNodeCoordinates = new ArrayList<Point>();
private int mGridNodesCount = 5;
private int mNodeGap = 100;
PathPoint mNodeCoordinates[][] = new PathPoint[mGridNodesCount][mGridNodesCount];

PathMeasure mPm;
float mStartCoordinates[] = {0f, 0f};
float mEndCoordinates[] = {0f, 0f};

PathPoint mPathPoint;

Boolean mNodesGridDrawn = false;

Bitmap mGameField = null;

public Boolean getNodesGridDrawn() {
return mNodesGridDrawn;
}

public Panel(Context context) {
super(context);

mNodeBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot);

mNodeBitmapWidthCenter = mNodeBitmap.getWidth()/2;
mNodeBitmapHeightCenter = mNodeBitmap.getHeight()/2;

mDotOK = BitmapFactory.decodeResource(getResources(), R.drawable.dot_ok);

getHolder().addCallback(this);
mViewThread = new ViewThread(this);

mPathPaint = new Paint();
mPathPaint.setAntiAlias(true);
mPathPaint.setDither(true); //for better color
mPathPaint.setColor(0xFFFFFF00);
mPathPaint.setStyle(Paint.Style.STROKE);
mPathPaint.setStrokeJoin(Paint.Join.ROUND);
mPathPaint.setStrokeCap(Paint.Cap.ROUND);
mPathPaint.setStrokeWidth(5);
}

public ArrayList<ArrayList<PathPoint>> getNodesHitPatterns()
{
return this.mNodesHitPatterns;
}

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {


}

public void surfaceCreated(SurfaceHolder holder) {

//setPadding(100, 100, 0, 0);

if (!mViewThread.isAlive()) {
mViewThread = new ViewThread(this);
mViewThread.setRunning(true);
mViewThread.start();
}
}

public void surfaceDestroyed(SurfaceHolder holder) {

if (mViewThread.isAlive()) {
mViewThread.setRunning(false);
}
}

//draw the basic nodes grid that the user will use to draw the lines on
//store as bitmap
public void drawNodesGrid(Canvas canvas)
{
canvas.drawColor(Color.WHITE);

for (int i = 0; i < mGridNodesCount; i++)
{
for (int j = 0; j < mGridNodesCount; j++)
{
int xPos = j * mNodeGap;
int yPos = i * mNodeGap;

try
{
//TODO - changed
mNodeCoordinates[i][j] = new PathPoint(xPos, yPos, null);
}
catch (Exception e)
{
e.printStackTrace();
}

canvas.drawBitmap(mNodeBitmap, xPos, yPos, null);
}
}

mNodesGridDrawn = true;

mGameField = Bitmap.createBitmap(mGridNodesCount * mNodeGap, mGridNodesCount * mNodeGap, Bitmap.Config.ARGB_8888);
}

public void doDraw(Canvas canvas)
{
canvas.drawBitmap(mGameField, 0f, 0f, null);

synchronized (mViewThread.getSurefaceHolder())
{
//draw path user is creating with her finger on screen
for (Path path : mGraphics)
{
//get path values
mPm = new PathMeasure(path, true);

mPm.getPosTan(0f, mStartCoordinates, null);
//System.out.println("aStartCoordinates X:" + aStartCoordinates[0] + " aStartCoordinates Y:" + aStartCoordinates[1]);
mPm.getPosTan(mPm.getLength(), mEndCoordinates, null);
//System.out.println("aEndCoordinates X:" + aEndCoordinates[0] + " aEndCoordinates Y:" + aEndCoordinates[1]);

//coordinates are within game board boundaries
if((mStartCoordinates[0] >= 1 && mStartCoordinates[1] >= 1) && (mEndCoordinates[0] >= 1 && mEndCoordinates[1] >= 1))
{
canvas.drawPath(path, mPathPaint);
}
}

//nodes that the path goes through, are repainted green
//these nodes are building the drawn pattern
for (ArrayList<PathPoint> nodePattern : mNodesHitPatterns)
{
for (PathPoint nodeHit : nodePattern)
{
canvas.drawBitmap(mDotOK, nodeHit.x - ((mDotOK.getWidth()/2) - (mNodeBitmap.getWidth()/2)), nodeHit.y - ((mDotOK.getHeight()/2) - (mNodeBitmap.getHeight()/2)), null);
}
}

this.destroyDrawingCache();
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {
synchronized (mViewThread.getSurefaceHolder()) {

if(event.getAction() == MotionEvent.ACTION_DOWN)
{
//System.out.println("Action downE x: " + event.getX() + " y: " + event.getY());

for (int i = 0; i < mGridNodesCount; i++)
{
for (int j = 0; j < mGridNodesCount; j++)
{
//TODO - changed
//PathPoint pathPoint = mNodeCoordinates[i][j];

mPathPoint = mNodeCoordinates[i][j];

if((Math.abs((int)event.getX() - mPathPoint.x) <= 35) && (Math.abs((int)event.getY() - mPathPoint.y) <= 35))
{
//mPath.moveTo(pathPoint.x + mBitmap.getWidth() / 2, pathPoint.y + mBitmap.getHeight() / 2);

//System.out.println("Action down x: " + pathPoint.x + " y: " + pathPoint.y);
ArrayList<PathPoint> newNodesPattern = new ArrayList<PathPoint>();
mNodesHitPatterns.add(newNodesPattern);
//mNodesHitPatterns.add(nh);
//pathPoint.setAction("down");
break;
}
}
}
}
else if(event.getAction() == MotionEvent.ACTION_MOVE)
{
final int historySize = event.getHistorySize();
//System.out.println("historySize: " + historySize);
//System.out.println("Action moveE x: " + event.getX() + " y: " + event.getY());

coordinateFound:
for (int i = 0; i < mGridNodesCount; i++)
{
for (int j = 0; j < mGridNodesCount; j++)
{
//TODO - changed
//PathPoint pathPoint = mNodeCoordinates[i][j];
mPathPoint = mNodeCoordinates[i][j];

if((Math.abs((int)event.getX() - mPathPoint.x) <= 35) && (Math.abs((int)event.getY() - mPathPoint.y) <= 35))
{
int lastPatternIndex = mNodesHitPatterns.size()-1;
ArrayList<PathPoint> lastPattern = mNodesHitPatterns.get(lastPatternIndex);
int lastPatternLastNode = lastPattern.size()-1;

if(lastPatternLastNode != -1)
{
if(!mPathPoint.equals(lastPattern.get(lastPatternLastNode).x, lastPattern.get(lastPatternLastNode).y))
{
lastPattern.add(mPathPoint);
//System.out.println("Action moveC [add point] x: " + pathPoint.x + " y: " + pathPoint.y);
}
}
else
{
lastPattern.add(mPathPoint);
//System.out.println("Action moveC [add point] x: " + pathPoint.x + " y: " + pathPoint.y);
}

break coordinateFound;
}
else //no current match => try historical
{
if(historySize > 0)
{
for (int k = 0; k < historySize; k++)
{
//System.out.println("Action moveH x: " + event.getHistoricalX(k) + " y: " + event.getHistoricalY(k));
if((Math.abs((int)event.getHistoricalX(k) - mPathPoint.x) <= 35) && (Math.abs((int)event.getHistoricalY(k) - mPathPoint.y) <= 35))
{
int lastPatternIndex = mNodesHitPatterns.size()-1;
ArrayList<PathPoint> lastPattern = mNodesHitPatterns.get(lastPatternIndex);
int lastPatternLastNode = lastPattern.size()-1;

if(lastPatternLastNode != -1)
{
if(!mPathPoint.equals(lastPattern.get(lastPatternLastNode).x, lastPattern.get(lastPatternLastNode).y))
{
lastPattern.add(mPathPoint);
//System.out.println("Action moveH [add point] x: " + pathPoint.x + " y: " + pathPoint.y);
}
}
else
{
lastPattern.add(mPathPoint);
//System.out.println("Action moveH [add point] x: " + pathPoint.x + " y: " + pathPoint.y);
}

break coordinateFound;
}
}
}
}
}
}
}
else if(event.getAction() == MotionEvent.ACTION_UP)
{
// for (int i = 0; i < mGridSize; i++) {
//
// for (int j = 0; j < mGridSize; j++) {
//
// PathPoint pathPoint = mNodeCoordinates[i][j];
//
// if((Math.abs((int)event.getX() - pathPoint.x) <= 35) && (Math.abs((int)event.getY() - pathPoint.y) <= 35))
// {
// //the location of the node
// //mPath.lineTo(pathPoint.x + mBitmap.getWidth() / 2, pathPoint.y + mBitmap.getHeight() / 2);
//
// //System.out.println("Action up x: " + pathPoint.x + " y: " + pathPoint.y);
//
// //mGraphics.add(mPath);
// // mNodesHit.add(pathPoint);
// // pathPoint.setAction("up");
// break;
// }
// }
// }
}

//System.out.println(mNodesHitPatterns.toString());

//create mPath
for (ArrayList<PathPoint> nodePattern : mNodesHitPatterns)
{
for (int i = 0; i < nodePattern.size(); i++)
{
if(i == 0) //first node in pattern
{
mPath.moveTo(nodePattern.get(i).x + mNodeBitmapWidthCenter, nodePattern.get(i).y + mNodeBitmapHeightCenter);
}
else
{
mPath.lineTo(nodePattern.get(i).x + mNodeBitmapWidthCenter, nodePattern.get(i).y + mNodeBitmapWidthCenter);
}

//mGraphics.add(mPath);
}
}

mGraphics.add(mPath);

return true;
}
}


}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~类“ ViewThread” ~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~

public class ViewThread extends Thread {
private Panel mPanel;
private SurfaceHolder mHolder;
private boolean mRun = false;

public ViewThread(Panel panel) {
mPanel = panel;
mHolder = mPanel.getHolder();
}

public void setRunning(boolean run) {
mRun = run;
}

public SurfaceHolder getSurefaceHolder()
{
return mHolder;
}

@Override
public void run()
{
Canvas canvas = null;
while (mRun)
{
canvas = mHolder.lockCanvas();
//canvas = mHolder.lockCanvas(new Rect(50, 50, 150, 150));
if (canvas != null)
{
if(!mPanel.getNodesGridDrawn())
{
mPanel.drawNodesGrid(canvas);
}

mPanel.doDraw(canvas);
mHolder.unlockCanvasAndPost(canvas);
}
}
}
}

最佳答案

这只是个主意,但我会尝试将所有声明从循环中取出。我知道将它们本地化可能很有用,但是通常这确实很耗时,因此可以有所帮助。我的第二个想法已经在更新中被您测试过了,所以现在我也很好奇它的发展;)

关于android-animation - Android 2D动画绘图:性能不佳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12650721/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com