Нужно сделать так, чтобы за пальцем двигалась картинка (Bitmap f), а и выполнялось "стирание",
но алгоритм движения картинки очень сильно нагружает устройство, и в итоге FPS=8. Без движения картинки "стирание" происходит при довольно большой частоте кадров. Как можно ускорить/оптимизировать этот код, чтобы картинка двигалась без лагов? Заранее ОГРОМНОЕ спасибо!
public class WScratchView extends SurfaceView implements SurfaceHolder.Callback
{
private Context mContext;
public WScratchViewThread mThread;
List
public WScratchView(Context ctx, AttributeSet attrs)
{
super(ctx, attrs);
init(ctx, attrs);
}
public WScratchView(Context context)
{
super(context);
init(context, null);
}
private void init(Context context, AttributeSet attrs)
{
mContext = context;
mOverlayColor = DEFAULT_COLOR;
mRevealSize = DEFAULT_REVEAL_SIZE;
setZOrderOnTop(true);
SurfaceHolder holder = getHolder();
holder.addCallback(this);
holder.setFormat(PixelFormat.TRANSPARENT);
mOverlayPaint = new Paint();
mOverlayPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
mOverlayPaint.setStyle(Paint.Style.STROKE);
mOverlayPaint.setStrokeCap(Paint.Cap.ROUND);
mOverlayPaint.setStrokeJoin(Paint.Join.ROUND);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.layer);
f = BitmapFactory.decodeResource(getResources(), R.drawable.f);
Resources res = getResources();
fHeight = res.getInteger(R.integer.fHeight);
fWidth = res.getInteger(R.integer.fWidth);
fIndent = res.getInteger(R.integer.fIndent);
h = new Handler();
updateScores = new Runnable() {
@Override
public void run()
{
Main.tvScores.setText(Long.toString(scores));
}
};
paint = new Paint();
paintf = new Paint();
paint.setFilterBitmap(true);
paintf.setFilterBitmap(false);
Log.d("LOG_", "init complete");
}
@SuppressLint("DrawAllocation") @Override
public void onDraw(Canvas canvas)
{
if (ignore_drawable)return;
destin = new Rect(0, 0, getWidth(), getHeight());
canvas.drawBitmap(bitmap, null, destin, paint);
//Log.d("LOG_","draw start");
for (Path path: mPathList)
{
mOverlayPaint.setAntiAlias(mIsAntiAlias);
mOverlayPaint.setStrokeWidth(mRevealSize);
canvas.drawPath(path, mOverlayPaint);
}
destinf = new Rect(fLeft, fTop, fRight, fBottom);
canvas.drawBitmap(f, null, destinf, paintf);
}
@Override
public boolean onTouchEvent(MotionEvent me)
{
ignore_drawable = true;
synchronized (mThread.getSurfaceHolder())
{
ignore_drawable = false;
if (!mIsScratchable)
{
return true;
}
if (!timerRunned)
{
timerRunned = true;
Main.cdt.start();
}
Log.d("LOG_", "bye");
switch (me.getAction())
{
case MotionEvent.ACTION_DOWN:
path = new Path();
path.moveTo(me.getX(), me.getY());
startX = me.getX();
startY = me.getY();
mPathList.add(path);
break;
case MotionEvent.ACTION_MOVE:
playrandom();
fX = (int)me.getRawX();
fY = (int)me.getRawY();
fLeft = fX - fIndent;
fTop = fY - fIndent - fIndent;
if (fLeft < 0)fLeft = 0;
if (fTop < 0) fTop = 0;
fRight = fX - fIndent + fWidth;
fBottom = fY - (fIndent*2) + fHeight;
if (mScratchStart)
{
path.lineTo(me.getX(), me.getY());
}
else
{
if (isScratch(startX, me.getX(), startY, me.getY()))
{
mScratchStart = true;
path.lineTo(me.getX(), me.getY());
}
}
scores += Main.level;
h.post(updateScores);
invalidate();
break;
case MotionEvent.ACTION_UP:
mScratchStart = false;
try
{phrase.stop();}
catch (Exception ex) {}
break;
}
invalidate();
return true;
}
}
public void playrandom()
{
//Тут идёт очень большой метод, не связанный с вопросом. Я его пропущу.
}
private boolean isScratch(float oldX, float x, float oldY, float y)
{
float distance = (float) Math.sqrt(Math.pow(oldX - x, 2) + Math.pow(oldY - y, 2));
if (distance > mRevealSize * 2)
{
return true;
}
else
{
return false;
}
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {}
@Override
public void surfaceCreated(SurfaceHolder arg0)
{
mThread = new WScratchViewThread(getHolder(), this);
mThread.setRunning(true);
mThread.setPriority(1);
mThread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0)
{
boolean retry = true;
mThread.setRunning(false);
while (retry)
{
try
{
mThread.join();
retry = false;
}
catch (InterruptedException e) {}
}
}
class WScratchViewThread extends Thread
{
private SurfaceHolder mSurfaceHolder;
private WScratchView mView;
private boolean mRun = false;
public WScratchViewThread(SurfaceHolder surfaceHolder, WScratchView view)
{
mSurfaceHolder = surfaceHolder;
mView = view;
}
public void setRunning(boolean run)
{
mRun = run;
}
public SurfaceHolder getSurfaceHolder()
{
return mSurfaceHolder;
}
@SuppressLint("WrongCall") @Override
public void run()
{
Canvas c;
while (mRun)
{
c = null;
try
{
c = mSurfaceHolder.lockCanvas(null);
if (c != null)
synchronized (mSurfaceHolder)
{
{
mView.onDraw(c);
}
}
}
finally
{
if (c != null)
{
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
try
{
TimeUnit.MILLISECONDS.sleep(50);
}
catch (InterruptedException e) {}
}
}
}
public void resetView()
{
synchronized (mThread.getSurfaceHolder())
{
mPathList.clear();
}
}
public boolean isScratchable()
{
return mIsScratchable;
}
public void setScratchable(boolean flag)
{
mIsScratchable = flag;
}
public void setOverlayColor(int ResId)
{
mOverlayColor = ResId;
}
public void setRevealSize(int size)
{
mRevealSize = size;
}
public void setAntiAlias(boolean flag)
{
mIsAntiAlias = flag;
}
}
Ответ
Только по коду сказать что-то конкретное сложно. Стоит прогнать ваше приложение через профайлер (насколько я помню, он входит в состав Android SDK) и проверить, какой метод отъедает больше всего времени. Точно не скажу, но мне кажется, что это метод onTouchEvent. Во-превых, лучше не использовать блок synchronized, такая синхронизация отъедает слишком много ресурсов. Вместо него лучше использовать локи (также почитайте про методы lockCanvas() и unlockCanvasAndPost()). Во-вторых, этот метод будет отрабатывать очень много раз в секунду на каждое касание, что скорее всего и нагружает процессор. Для того, чтобы этого избежать стоит ограничить число срабатываний этого метода в секунду. Для этого подойдёт проверка на время предыдкщего срабатывания метода: если он отработал меньше чем, скажем, 50 милисекунд назад, то не вызываем обработчик.
Комментариев нет:
Отправить комментарий