Страницы

Поиск по вопросам

пятница, 5 июля 2019 г.

Как оптимизировать код?

Нужно сделать так, чтобы за пальцем двигалась картинка (Bitmap f), а и выполнялось "стирание", но алгоритм движения картинки очень сильно нагружает устройство, и в итоге FPS=8. Без движения картинки "стирание" происходит при довольно большой частоте кадров. Как можно ускорить/оптимизировать этот код, чтобы картинка двигалась без лагов? Заранее ОГРОМНОЕ спасибо! public class WScratchView extends SurfaceView implements SurfaceHolder.Callback { private Context mContext; public WScratchViewThread mThread; List mPathList = new ArrayList(); private int mOverlayColor; private Paint mOverlayPaint; private int mRevealSize; private boolean mIsScratchable = true; private boolean mIsAntiAlias = false; private Path path; private float startX = 0; private float startY = 0; private boolean mScratchStart = false; private MediaPlayer phrase; Boolean timerRunned = false; int fWidth,fHeight, fX,fY, fIndent; boolean ignore_drawable = false; Bitmap bitmap, f; public static long scores = 0; public Paint paint, paintf; public Rect destin, destinf; public int fLeft, fTop, fRight, fBottom; Handler h; Runnable updateScores;
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 милисекунд назад, то не вызываем обработчик.

Комментариев нет:

Отправить комментарий