3

EDIT: I took a look at the LogCat, and it said that it couldn't inflate com.example.playground. I then realized that it needed to me com.game.myapp.Playground. It worked after I changed it.

I recently asked why gravity wasn't working in my Android app (link) and I still have trouble with it. I changed the view to class "Playground" but now it just force closes. What am I doing wrong?

package com.game.myapp;

import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;


public class InGame extends Activity{

Playground v;

private int radius;
    private int xPosition;
    private int yPosition;
    private Paint paint;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Rewrite this, it sucks. Seriously.
        super.onCreate(savedInstanceState);
        v = new Playground(this);
        setContentView(v);
    }

    public InGame(int x, int y, int radius, int color)
    { 
        this.xPosition = x; this.yPosition = y; this.radius = radius;
        paint = new Paint(color);
    }

    void moveBall(int x, int y){
         xPosition = x; yPosition =y;        
    } 

    void onDraw(Canvas canvas){
          canvas.drawCircle(xPosition, yPosition, radius, paint);
    }    
}

Playground class:

package com.game.myapp;

import android.content.Context;
import android.graphics.Canvas;
import android.view.View;

public class Playground extends View{

public static InGame ball;

public Playground(Context context) {
    super(context);
    // TODO Auto-generated constructor stub
} 


   @Override
   public void onDraw(Canvas canvas)
   {
       super.onDraw(canvas);
       if (ball != null ){
           ball.onDraw(canvas);
       }
   }

}

Heres the LogCat:

11-04 16:36:33.945: D/dalvikvm(13177): newInstance failed: no <init>()

11-04 16:36:33.949: D/AndroidRuntime(13177): Shutting down VM

11-04 16:36:33.949: W/dalvikvm(13177): threadid=1: thread exiting with uncaught exception (group=0x4001e578)

11-04 16:36:33.953: E/AndroidRuntime(13177): FATAL EXCEPTION: main

11-04 16:36:33.953: E/AndroidRuntime(13177): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.game.myapp/com.game.myapp.InGame}: java.lang.InstantiationException: com.game.myapp.InGame

11-04 16:36:33.953: E/AndroidRuntime(13177):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1573)

11-04 16:36:33.953: E/AndroidRuntime(13177):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1667)

11-04 16:36:33.953: E/AndroidRuntime(13177):    at android.app.ActivityThread.access$1500(ActivityThread.java:117)

11-04 16:36:33.953: E/AndroidRuntime(13177):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935)

11-04 16:36:33.953: E/AndroidRuntime(13177):    at android.os.Handler.dispatchMessage(Handler.java:99)

11-04 16:36:33.953: E/AndroidRuntime(13177):    at android.os.Looper.loop(Looper.java:130)

11-04 16:36:33.953: E/AndroidRuntime(13177):    at android.app.ActivityThread.main(ActivityThread.java:3687)

11-04 16:36:33.953: E/AndroidRuntime(13177):    at java.lang.reflect.Method.invokeNative(Native Method)

11-04 16:36:33.953: E/AndroidRuntime(13177):    at java.lang.reflect.Method.invoke(Method.java:507)

11-04 16:36:33.953: E/AndroidRuntime(13177):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)

11-04 16:36:33.953: E/AndroidRuntime(13177):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)

11-04 16:36:33.953: E/AndroidRuntime(13177):    at dalvik.system.NativeStart.main(Native Method)

11-04 16:36:33.953: E/AndroidRuntime(13177): Caused by: java.lang.InstantiationException: com.game.myapp.InGame

11-04 16:36:33.953: E/AndroidRuntime(13177):    at java.lang.Class.newInstanceImpl(Native Method)

11-04 16:36:33.953: E/AndroidRuntime(13177):    at java.lang.Class.newInstance(Class.java:1409)

11-04 16:36:33.953: E/AndroidRuntime(13177):    at android.app.Instrumentation.newActivity(Instrumentation.java:1021)

11-04 16:36:33.953: E/AndroidRuntime(13177):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1565)

11-04 16:36:33.953: E/AndroidRuntime(13177):    ... 11 more
Community
  • 1
  • 1
Jordan
  • 249
  • 3
  • 8
  • 2
    Hi Jordan. Why have you tried to put all of the code in the Ball class in your activity? you should not try to use an activity as the ball! You know, it would be quicker for me to write this for you and just post it! Please, please, please take my advice. Learn about classes and object oriented programming and then try to tackle Android. You will not be successful, and will lose a lot of time in the process, if you don't understand the basics of OOP. – Simon Nov 05 '12 at 21:14

2 Answers2

4

Here's the complete code. I just wrote this and tested it. It works. I added a timer to the activity to move the ball right and down by 10 pixels every second. Please study it, learn from it and adapt it to your needs.

Ball class.

package com.example;

import android.graphics.Canvas;
import android.graphics.Paint;

public class Ball{

    private int radius;
    private int xPosition;
    private int yPosition;
    private int color;
    private Paint paint;

    public Ball(int x, int y, int radius, int color)
    {
        this.xPosition = x; this.yPosition = y; this.radius = radius;
        paint = new Paint();
        paint.setColor(color);
    }

    int getX(){return this.xPosition;}
    int getY(){return this.yPosition;}

    void moveBall(int x, int y){
        xPosition = x; yPosition =y;
    }

    void onDraw(Canvas canvas){
        canvas.drawCircle(xPosition, yPosition, radius, paint);
    }

}

Playground class

package com.example;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.ImageView;

public class Playground extends ImageView {

    private Ball ball;

    public Playground(Context context) {
        this(context,null);
    }

    public Playground(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public Playground(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setBall(Ball ball){
        this.ball = ball;
    }

    @Override
    public void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
        if (ball != null ){
            ball.onDraw(canvas);
        }
    }

}

Activity class

package com.example;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;

import java.util.Timer;
import java.util.TimerTask;

public class MyActivity extends Activity {
    /**
     * Called when the activity is first created.
     */

    Playground playground;
    Ball ball;
    Timer myTimer;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        playground = (Playground) findViewById(R.id.playground);

        ball = new Ball(100, 100, 20, Color.RED);

        playground.setBall(ball);

        myTimer = new Timer();
        myTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                Update();
            }

        }, 0, 1000);
    }

    private void Update() {
        this.runOnUiThread(moveBall);
    }

    private Runnable moveBall = new Runnable() {
        public void run() {
            ball.moveBall(ball.getX() + 10, ball.getY() + 10);
            playground.invalidate();
        }
    };


}

[EDIT] The XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent">
    <com.example.Playground
            android:id="@+id/playground"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"/>
</LinearLayout>

Key points for OOP.

The Ball has no knowledge of the Playground or the activity. It has a method that might get called by something asking it do draw on a canvas but for all it knows, it might be an invisible canvas, or a canvas of a button, or a canvas of a bitmap - it doesn't know or need to know. It's the job of whatever calls the method to worry about that.

The Playground has no knowledge of the activity or the Ball. It knows it might have an instance of a Ball class and if it has, it should call it's onDraw method but it has no idea what the ball is or what it draws. The Ball worries about that.

The activity has no knowledge of the Ball or the Playground other than it has one of each and calls the Ball move method then tells the Playground to redraw itself.

The point is, you could change the draw methods, the move methods and everything else without recoding (OK, in general). For example, you could change the onDraw in the Ball class to draw a rectangle. Of course, the name of the class is now a bad choice but you get the idea...

Simon
  • 14,407
  • 8
  • 46
  • 61
  • Wow! It makes a lot more sense now! I used the exact code, yet it force closes, though. As the Activity class, I put my main class, MainActivity, and the xml from the MainActivity, activity_main.xml. I'm not sure what is going on, so I'm putting the LogCat up right now. Thanks though, it looks a lot cleaner & easier! – Jordan Nov 06 '12 at 03:11
  • Also, once I fix this, I will try and tackle OOP first, I (and you) feel as if Android would be a lot easier if I learned that, first. – Jordan Nov 06 '12 at 03:17
  • I'm getting an error in the playground class: In public setBall(Ball ball), it says "Return type for the method is missing" so it wants me to change it to public void. But when I change it, it force closes. the LogCat is in the post. – Jordan Nov 07 '12 at 03:14
  • I needed to change the com.example.Playground to me package name.Playground. Thanks for all of your help! I'm going to learn about OOP now :) – Jordan Nov 07 '12 at 03:23
2

You have no default constructor in your InGame Activity, which is necessary for Android to be able to instantiate it.

The presence of an explicit constructor will cause no implicit no-arg constructor to be defined. You may need to provide your own no-arg constructor that initializes its members to default values.

I would delete the explicit constructor and put the initialization into the onCreate(Bundle) method.

nicholas.hauschild
  • 42,483
  • 9
  • 127
  • 120