Search code examples
javaandroidandroid-custom-viewsurfaceview

Cannot draw on canvas with custom view


I have a class GameActivityas follows (I just post the relevant part):

public class GameActivity extends AppCompatActivity {

// initiate variables
private GameView mGameView;
private Display mDisplay;
private Point mSize;

public static int window_width = 0;
public static int window_height = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

    mDisplay = getWindowManager().getDefaultDisplay();
    mSize = new Point();
    mDisplay.getSize(mSize);
    window_width = mSize.x;
    window_height = mSize.y;

    // initialize game view object
    mGameView = new GameView(this);

    // adding it to the content view
    //setContentView(mGameView);
    setContentView(R.layout.activity_game);
}

And I have the class GameView as follows with two constructors because of the custom view (also just the relevant parts to keep it clear):

private Context mContext;

//These objects will be used for drawing
private SurfaceHolder mSurfaceHolder;
private Paint mPaint;

public GameView(Context context){
    super(context);

    Log.d("TEST","Constructor 1");

    init(context, null);

    // clear all lists
    ...

    // create object of map in beginning of game
    ...

    // create objects of HQs
    ...

   // create other sprite objects and add them to lists
   ...
}

public GameView(Context context, AttributeSet attrs) {
    super(context, attrs);

    Log.d("TEST","Constructor 2");

    init(context, attrs);

}

And I call in both of the constructors the init() method

private void init(Context context, AttributeSet attrs) {
    mContext = context;
    mSurfaceHolder = getHolder();
    mPaint = new Paint();
    mPaint.setColor(Color.DKGRAY);
}

My run() is like this:

@Override
public void run(){


    Log.d("TEST","RUN");
    long current_time = 0;
    long old_time;


    while (playing) {
        old_time = current_time;


        // update the game
        update();

        //to draw the frame
        //onDraw(canvas);
        draw();

        //to control (lets the game sleep for some milliseconds)
        control();

        current_time = SystemClock.elapsedRealtime();

        frametime = current_time - old_time;
        framerate = 1000/ (current_time - old_time);

    }
}

And the draw() (where the mistake happens) is like this:

private void draw() {
    // BUG: mSurfaceHolder.getSurface.isValid ist niemals valid

    Canvas canvas;

    //if(true){
    //checking if surface is valid
    if (mSurfaceHolder.getSurface().isValid()) {
        Log.d("Test","DRAW");

        //locking the canvas
        canvas = mSurfaceHolder.lockCanvas();

        //drawing a background color for canvas
        canvas.drawColor(Color.GREEN);

        // call draw methods here
        // bigger objects should be called before smaller objects for visibility
        draw_ground(canvas);
        draw_hq(canvas);
        draw_soldiers(canvas);
        draw_bullets(canvas);
        draw_HUD(canvas);

        //Unlocking the canvas
        mSurfaceHolder.unlockCanvasAndPost(canvas);
    }
}

No the question is: If I in the first class GameActivity pass the object mGameView of the class GameView to setContentView everything is fine and the draw() methods works normal which means mSurfaceHolder.getSurface().isValid()) is valid.

But if I put in the first class setContentView(R.layout.activity_game); then mSurfaceHolder.getSurface().isValid()) is never valid. Everything else works (e.g. I hear the game sound) but he doesn't draw. If I don't check for mSurfaceHolder.getSurface().isValid()) then the game crashes because in the code below in draw() the canvas is empty.

My aim is to create a custom view and overlay this with buttons.

Here is the XML:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".GameActivity">



<!--Test-->

<com.example.mirco.battlefront.GameView
    android:id="@+id/gameView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<Button
    android:id="@+id/button"
    android:layout_width="119dp"
    android:layout_height="wrap_content"
    android:text="Button" />


<!--Test-->
</FrameLayout>

The XML seems to be correct because Android Studio recognizes it (custom view with overlayed button). But he doesn't draw in it. enter image description here

Like I said with setContentView(mGameView); everything is fine except that I only have one view where I can't overlay buttons and so on which is not what I want.

What am I doing wrong? I tried to follow that LINK as good as possible. I am trying for days now to solve this but also can't find the solution anywhere.


Solution

  • Instead of

    mGameView = new GameView(this);
    
        // adding it to the content view
        //setContentView(mGameView);
        setContentView(R.layout.activity_game);
    

    You should do

    setContentView(R.layout.activity_game);
    mGameView = (GameView)findViewById (R.id.gameView);
    

    Then the mGameview is the one in your layout.