#android #canvas
Нужно сделать так, чтобы за пальцем двигалась картинка (Bitmap f), а и выполнялось "стирание", но алгоритм движения картинки очень сильно нагружает устройство, и в итоге FPS=8. Без движения картинки "стирание" происходит при довольно большой частоте кадров. Как можно ускорить/оптимизировать этот код, чтобы картинка двигалась без лагов? Заранее ОГРОМНОЕ спасибо! public class WScratchView extends SurfaceView implements SurfaceHolder.Callback { private Context mContext; public WScratchViewThread mThread; ListmPathList = 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; } }
Ответы
Ответ 1
Только по коду сказать что-то конкретное сложно. Стоит прогнать ваше приложение через профайлер (насколько я помню, он входит в состав Android SDK) и проверить, какой метод отъедает больше всего времени. Точно не скажу, но мне кажется, что это метод onTouchEvent. Во-превых, лучше не использовать блок synchronized, такая синхронизация отъедает слишком много ресурсов. Вместо него лучше использовать локи (также почитайте про методы lockCanvas() и unlockCanvasAndPost()). Во-вторых, этот метод будет отрабатывать очень много раз в секунду на каждое касание, что скорее всего и нагружает процессор. Для того, чтобы этого избежать стоит ограничить число срабатываний этого метода в секунду. Для этого подойдёт проверка на время предыдкщего срабатывания метода: если он отработал меньше чем, скажем, 50 милисекунд назад, то не вызываем обработчик.
Комментариев нет:
Отправить комментарий