(Android Studio) My Canvas is being drawn to, no errors, but it does NOT update the screen

I’m making a solitaire game for Android and so far I’ve managed to figure everything necessary out, except for the Canvas. The Canvas is being locked, drawn to, unlocked and posted, but it is NOT updating the screen.

The whole screen will draw initially, cards and all, but will never update again except until the thread throws an IllegalThreadStateException. (by putting the app into the background, by hitting the home button, or the recent apps button.)

A lot of my code was copied from tutorials in an attempt to get it working in a state I can test it in.

I am a complete beginner to Android API and so far, I absolutely hate it. Please tell me if I did anything stupid, even at all.

Target API is at 34, minimum is set to 21. My device is a physical device; TCL 10 Pro, 6.47″, API 30. Doesn’t throw anything about API, though.

Here is my custom Thread source:

public class MainThread extends Thread {
    private final SurfaceHolder surfaceHolder;
    private final GameBoard boardView;
    private boolean running;
    public static Canvas canvas;
    public MainThread(SurfaceHolder surfaceHolder, GameBoard boardView) {
        super();
        this.surfaceHolder = surfaceHolder;
        this.boardView = boardView;
    }
    public void setRunning(boolean isRunning) {
        running = isRunning;
    }
    @Override
    public void run() {
        while (running) {
            canvas = null;
            try {
                canvas = this.surfaceHolder.lockCanvas();
                synchronized(surfaceHolder) {
                    this.boardView.update();
                    this.boardView.draw(canvas);
                }
            } catch (Exception e) {
                System.out.println("CATCH");
            } finally {
                if (canvas != null) {
                    try {
                        surfaceHolder.unlockCanvasAndPost(canvas);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

Here is my (shortened) custom SurfaceView source:

public class GameBoard extends SurfaceView implements SurfaceHolder.Callback {
    BaseSingleDeckGameObject gameObject;
    private final MainThread thread;

// shorter constructors were here

    public GameBoard(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(attrs, defStyle); //shorter constructors set these to (null, 0)
        getHolder().addCallback(this);
        thread = new MainThread(getHolder(), this);
        setFocusable(true);
        gameObject = new KlondikeGameObject(0, context);
    }

    public void update() {
        gameObject.updateGame();
    }

    private void init(AttributeSet attrs, int defStyle) {
        this.setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_FULLSCREEN
        );
    }

    public boolean onTouchEvent(MotionEvent motion) {
        gameObject.doTouchEvent(motion); //this just prints out the information from MotionEvent to console, and sets 2 variables.
        //performClick
        return true;
    }
// performClick is here

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        if (canvas != null) {
            gameObject.drawGame(canvas);
        }
    }

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        thread.setRunning(true);
        thread.start();
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        boolean retry = true;
        while (retry) {
            try {
                thread.setRunning(false);
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            retry = false;
        }
    }
}

Here is my custom AppCompatActivity source:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        this.setContentView(R.layout.game_screen);
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder(StrictMode.getVmPolicy())
                .detectLeakedClosableObjects()
                .build());
    }

    @Override
    protected void onResume() {
        super.onResume();
    }
}

The only 2 problems I’m really having, is getting the screen to update, and the Thread errors every time the Surface is destroyed, and then created.

Here is the error thrown:

Exception configuring surface
java.lang.IllegalThreadStateException
    at java.lang.Thread.start(Thread.java:872)
    at com.severinghams.homebrewsolitaire.GameBoard.surfaceCreated(GameBoard.java:113)
    at android.view.SurfaceView.updateSurface(SurfaceView.java:1208)
    at android.view.SurfaceView.setWindowStopped(SurfaceView.java:294)
    at android.view.SurfaceView.surfaceCreated(SurfaceView.java:1699)
    at android.view.ViewRootImpl.notifySurfaceCreated(ViewRootImpl.java:1796)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2798)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2008)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8343)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1136)
    at android.view.Choreographer.doCallbacks(Choreographer.java:958)
    at android.view.Choreographer.doFrame(Choreographer.java:882)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1121)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:236)
    at android.app.ActivityThread.main(ActivityThread.java:7904)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:952)

I cannot find any documentation/examples on the standard use of drawing to a Canvas on a SurfaceView, so I’m stumped. I cannot figure out what I did wrong, but I know it isn’t anything in the custom class, because it DOES draw everything, the Thread is executing code in the SurfaceView’s draw() method, the Thread does not error, or throw, or cause any problems when it unlocks and posts, and the temporary cursor does show up. Screenshot

onTouchEvent calls a method in my game class, which sets position variables inside the game class. Then the draw() method calls drawGame() inside my game class, which should draw a square at the location provided, but it doesnt update the screen.

The white square only moves after the thread exception is thrown, but only once. It will update again when it tries to create again.

My apologies for my incredibly stilted and meandering explanation of the problem, and clear lack of brevity. In my attempts to truncate my explanation, it just becomes more disjointed.

Any help would be appreciated! I am truly stumped!

New contributor

SeveringHams is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật