Использование холста Android в другом классе, отладка ошибок сбоя - PullRequest
0 голосов
/ 10 ноября 2018

Просто начинаю с Android, canvas, работ. У меня есть существующий код Java, который может рисовать фигуры на графическом объекте. Я пытаюсь использовать этот код в приложении для Android с Canvas. По сути, я пытаюсь избежать рефакторинга всего моего Java-кода для явного использования Canvas. Итак, я нахожусь в процессе создания своего собственного объекта «Графика». Все, что нужно сделать, это вызвать соответствующие методы Canvas для рисования указанной фигуры.

Я прочитал несколько постов о невозможности использования объекта canvas вне метода onDraw(). Насколько я понимаю, вы не можете передать объект canvas другому классу и ожидать, что он будет работать правильно. Но у меня также нет полного понимания того, как все это работает.

Приложение вылетает в классе Graphics в методе drawOval. Я прочитал журнал обо всем этом, но я не нашел хорошего ответа относительно того, почему это конкретно не работает. Я не смог найти способ получить журналы сбоев дружественным для Java способом (он же трассировка стека). Это просто бросает Fatal signal 11 (SIGSEGV), code 1, fault addr 0x130 in tid 1520.

Спасибо! Дайте мне знать, если нужно больше деталей. Вот мой код:

MainActivity

public class MainActivity extends AppCompatActivity {

    MyCanvas canvas;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        canvas = new MyCanvas(this);
        setContentView(canvas);
    }
}

MyCanvas View

public class MyCanvas extends View {
    Graphics graphics;
    List<Shape> shapes;

    public MyCanvas(Context context) {
        super(context);
        graphics = new Graphics();
        shapes = new ArrayList<>();
    }

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        graphics.setCanvas(canvas); //Sets the canvas object in the graphics class
        for (Shape shape : shapes) {
            try { //this is in a try/catch block for custom exception handling
                //This just calls the specific shapes render method,
                //in this case, a circle from the makeShape Method
                //The graphics object then calls the specific shape to
                //render on the canvas
                shape.render(graphics, 0, 0); 
            } catch (ShapeException e) {
                e.printStackTrace();
            }
        }
        invalidate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                int x = (int) event.getX();
                int y = (int) event.getY();
                try { //this is in a try/catch block for custom exception handling
                    makeShape(x, y);
                } catch (ShapeException e) {
                    e.printStackTrace();
                }
                invalidate();

            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: {
                break;
            }
        }
        invalidate();
        return true;
    }

    public void makeShape(int x, int y) throws ShapeException{
        Point p = new Point(x, y);
        Shape shape = new Circle(p, 50, 50);
        shapes.add(shape);
    }

}

Graphics

public class Graphics {
    private Canvas canvas = null;

    public Graphics() {
    }

    public void setCanvas(Canvas canvas) {
        if (this.canvas == null) {
            this.canvas = canvas;
        }
    }

    public void drawOval(int x, int y, int width, int height) {
        Paint paint1 = new Paint();
        paint.setColor(Color.BLACK);
        canvas.drawCircle(500, 500, 50, paint1); //App crashes here
    }
}

1 Ответ

0 голосов
/ 10 ноября 2018

У вас есть небольшое недопонимание относительно возможности передать Canvas различным классам. В этом нет абсолютно ничего плохого; передача холста методу класса - это то же самое, что и передача его в обычную функцию. Даже сохранение ссылки Canvas в переменной-члене ничего не повредит.

ОДНАКО, вышеизложенное верно только при том понимании, что Canvas нельзя использовать за пределами метода draw() / onDraw(). То есть любой метод, использующий Canvas, должен вызываться из onDraw(), или функция, вызываемая onDraw() и т. Д.

Это потому, что Canvas инициализируется (каркасом) непосредственно перед onDraw(), чтобы подготовиться к текущей операции рисования. Возможно, вы захотите думать об этом как об инициализации Canvas с Bitmap, который будет служить выходной поверхностью рисования для этого конкретного кадра экрана (что недалеко от истины). Как только onDraw() вернулось, фреймворк предполагает, что ваш код больше не будет его использовать, и может передать поверхность вывода / Bitmap / etc. на экран композитора для рендеринга, не опасаясь дальнейших изменений.

И ваш подход хорош как метод адаптации существующего кода для использования нового графического объекта.

Итак, для устранения сбоя: SIGSEGV никогда не должны происходить при нормальной разработке Android, когда вы не имеете дело (напрямую) с собственными / JNI-процедурами. Однако мне приходит в голову, что вы не обновляете объект Canvas в случае его изменения. Это может вызывать сбой (в собственном коде, поэтому вы не получаете трассировку стека Java). Вы использовали старый Canvas после того, как вам дали новый. Удалите условие if (this.canvas == null) и все будет в порядке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...