views:

625

answers:

2

I'm having some issues with the old "Cannot make a static reference to a non-static method" error in my Android program. I am creating a sand falling game (similar to the Powder Game) and I created a class called Control to create a Control Bar at the bottom of the screen with a slider for brush size (that works fine) and a button to pop up a Dialog to allow users to pick the selected element. However, when I call DemoActivity.showDialog(2) from my code, it gives the static reference to non-static error (DemoActivity is the main activity of my application). I also tried changing it to just Activity.showDialog(2), but I got exactly the same error! Please help, what am I doing wrong? Here's my code and thanks in advance:

package sand.falling.opengl;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.SeekBar;

public class Control extends LinearLayout
{
    private ImageButton control_button;
    private SeekBar brush_size_slider;

    final CharSequence[] elementslist = {"Sand", "Water", "Plant", "Wall", "Fire", "Ice", "Generator", "Oil", "Magma", "Stone", "C4"};

    public Control(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    @Override
    protected void onFinishInflate()
    {
        control_button = (ImageButton) findViewById(R.id.element_picker_button);
        brush_size_slider = (SeekBar) findViewById(R.id.brush_size_slider);

        control_button.setOnClickListener
            (
                    new OnClickListener()
                    {
                        public void onClick(View v)
                        {
                            //THIS DOESN'T WORK!!!!
                            DemoActivity.showDialog(2); //Run the element picker dialog
                        }
                    }
            );
        control_button.setImageResource(R.drawable.palette);

        brush_size_slider.setOnSeekBarChangeListener
            (
                    new SeekBar.OnSeekBarChangeListener()
                    {
                        public void onProgressChanged(SeekBar seekbar, int progress, boolean fromTouch)
                        {
                            int p = 32 * progress/100;
                            DemoActivity.setBrushSize(p);
                            Log.v("DemoActivity", "size:" + p);
                        }
                        public void onStartTrackingTouch(SeekBar seekbar) {}
                        public void onStopTrackingTouch(SeekBar seekbar) {}
                    }
            );
        brush_size_slider.setProgress((int)400/32);
    }
}

EDIT: I fixed it by adding the following to my Control.java code:

public class Control extends LinearLayout
{
    private DemoActivity activity;
        ...
    public void setActivity(DemoActivity act)
    {
        activity = act;
    }
        ...
        //Set a click listener for the button which should pop up element picker dialog when clicked
        control_button.setOnClickListener
            (
                    new OnClickListener()
                    {
                        public void onClick(View v)
                        {
                            activity.showDialog(2); //Run the element picker dialog
                        }
                    }
            );
}

And then calling control.setActivity(this); from my onResume section of DemoActivity.java! Hope it helps those of you with similar issues!!

+5  A: 

You have to call showDialog on a DemoActivity instance, NOT on the class itself. The only time you can call ClassName.methodName() is if the method is defined as static. showDialog is not a static method.

To fix this, you either need to instantiate a new DemoActivity or get an existing one, then call showDialog on that.

Edit: If you already have a DemoActivity instance when you instantiate this Control object, perhaps the following modification will work:

public class Control extends LinearLayout
{

    ...

    // add an Activity instance
    private Activity activity;

    // set the Activity in your constructor
    public Control(Context context, AttributeSet attrs, Activity activity)
    {
        super(context, attrs);
        this.activity = activity;
    }

    @Override
    protected void onFinishInflate()
    {
        ...

           // Use the instance activity here
           activity.showDialog(2);
        ...
    }
}
Kaleb Brasee
Ah, I think I get it. How would I go about getting a reference to a specific instance of the DemoActvity class. AFAIK, I don't create one myself, Android does it automatically when the user runs my app, so how do I reference it? Thanks for the rapid answer btw!
Looterguf
Hmm, not sure, I haven't done any Android development yet. I'll take a look for DemoActivity documentation. Does DemoActivity have a `instance()` or `getInstance()` method? If so, that might be what you need.
Kaleb Brasee
Well, DemoActivity is a class that I created that extends the general Activity class contained in the basic Android code. I looked up the documentation for Activity in Android, and there is a function called getInstanceCount(), but nothing like just instance() or getInstance().
Looterguf
If you've got an existing DemoActivity instance outside of the Control class, you could probably pass it into the Control constructor, save it as a attribute of Control, then use it down in `onFinishInflate()`.
Kaleb Brasee
I tried your edit, and it fixed the error, however when I run my app in the emulator and click on the button, it crashes with a NullPointerException at Line 42 of Control.java: activity.showDialog(2); //Run the element picker dialogI'm not quite sure why.
Looterguf
In case it helps, it says for the line:this.activity = activitythat it has no effect. I think this is because this.activity is basically just referring to the variable activity, and it sets it equal to itself.
Looterguf
You'd also need to update the constructor from `public Control(Context context, AttributeSet attrs)` to `public Control(Context context, AttributeSet attrs, Activity activity)` and pass in a valid Activity instance when you create the Control.
Kaleb Brasee
Well, I added that, but I don't actually call the constructor, I use the following code: public Control control; public SandView sand_view; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //Uses onCreate from the general Activity requestWindowFeature(Window.FEATURE_NO_TITLE); //Get rid of title bar setContentView(R.layout.sand); sand_view = (SandView) findViewById(R.id.sand_view); control = (Control) findViewById(R.id.control);
Looterguf
A: 

I managed to fix this, read the edit in my question for details. Thanks for the response Kaleb! It really helped me understand the problem, so that I was able to solve it!

Looterguf