Java – Drawing to Canvas using custom methods?

Drawing to Canvas using custom methods?… here is a solution to the problem.

Drawing to Canvas using custom methods?

I’m writing code for an Android 2-D game and I’m having some trouble.

Currently, in my package, I have a thread that is drawn on a Canvas instance. I’m drawing a drawable bitmap from a resource. What I want to do is let the thread handle the drawing of the background image. But enable instances of custom objects to be drawn onto the same Canvas using drawables. This seems logically possible, but I can’t get it to work. Whenever I try to retrieve a resource in a custom class, the application crashes on startup.

Here are some of my efforts: (If I do something stupid, don’t laugh, I’m working on it.) )

public class Worker{

Get drawables
  Resources res = getResources();
  Drawable man1 = res.getDrawable(R.drawable.workertest);

  Context mContext;
  Resources res = mContext.getResources();

  Drawable man1 = mContext.getResources().getDrawable(R.drawable.workertest);
  Drawable man2 = mContext.getResources().getDrawable(R.drawable.workertest1);

  Drawable man1 = res.getDrawable(R.drawable.workertest);
  Drawable man2 = res.getDrawable(R.drawable.workertest1);

}

As you can see, I’ve tried a few different approaches, and I’ve also tried adding (extension activities) to my class (class), but I can’t figure this out.

This code doesn’t solve the problem of actually drawing to Canvas, I haven’t crossed that bridge yet

Edit: This is an activity. As you can see, it calls a thread in LunarView. The thread instantiates the object that needs to retrieve the Drawable. How do I get the application context for an object? Or is there another way? Yes, this is the code from the android sample code.

public class LunarLander extends Activity {
    private static final int MENU_EASY = 1;

private static final int MENU_HARD = 2;

private static final int MENU_MEDIUM = 3;

private static final int MENU_PAUSE = 4;

private static final int MENU_RESUME = 5;

private static final int MENU_START = 6;

private static final int MENU_STOP = 7;

/** A handle to the thread that's actually running the animation. */
    public static LunarThread mLunarThread;

/** A handle to the View in which the game is running. */
    public LunarView mLunarView;

/**
     * Invoked during init to give the Activity a chance to set up its Menu.
     *
     * @param menu the Menu to which entries may be added
     * @return true
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);

menu.add(0, MENU_START, 0, R.string.menu_start);
        menu.add(0, MENU_STOP, 0, R.string.menu_stop);
        menu.add(0, MENU_PAUSE, 0, R.string.menu_pause);
        menu.add(0, MENU_RESUME, 0, R.string.menu_resume);
        menu.add(0, MENU_EASY, 0, R.string.menu_easy);
        menu.add(0, MENU_MEDIUM, 0, R.string.menu_medium);
        menu.add(0, MENU_HARD, 0, R.string.menu_hard);

return true;
    }

/**
     * Invoked when the user selects an item from the Menu.
     *
     * @param item the Menu entry which was selected
     * @return true if the Menu item was legit (and we consumed it), false
     *         otherwise
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case MENU_START:
                mLunarThread.doStart();
                return true;
            case MENU_STOP:
                mLunarThread.setState(LunarThread.STATE_LOSE,
                        getText(R.string.message_stopped));
                return true;
            case MENU_PAUSE:
                mLunarThread.pause();
                return true;
            case MENU_RESUME:
                mLunarThread.unpause();
                return true;
            case MENU_EASY:
                mLunarThread.setDifficulty(LunarThread.DIFFICULTY_EASY);
                return true;
            case MENU_MEDIUM:
                mLunarThread.setDifficulty(LunarThread.DIFFICULTY_MEDIUM);
                return true;
            case MENU_HARD:
                mLunarThread.setDifficulty(LunarThread.DIFFICULTY_HARD);
                return true;
        }

return false;
    }

/**
     * Invoked when the Activity is created.
     *
     * @param savedInstanceState a Bundle containing state saved from a previous
     *        execution, or null if this is a new execution
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

 tell system to use the layout defined in our XML file
        setContentView(R.layout.lunar_layout);

 get handles to the LunarView from XML, and its LunarThread
        mLunarView = (LunarView) findViewById(R.id.lunar);
        mLunarThread = mLunarView.getThread();

 give the LunarView a handle to the TextView used for messages
        mLunarView.setTextView((TextView) findViewById(R.id.text));

if (savedInstanceState == null) {
             we were just launched: set up a new game
            mLunarThread.setState(LunarThread.STATE_READY);
            Log.w(this.getClass().getName(), "SIS is null");
        } else {
             we are being restored: resume a previous game
            mLunarThread.restoreState(savedInstanceState);
            Log.w(this.getClass().getName(), "SIS is nonnull");
        }
    }

/**
     * Invoked when the Activity loses user focus.
     */
    @Override
    protected void onPause() {
        super.onPause();
        mLunarView.getThread().pause();  pause game when Activity pauses
    }

/**
     * Notification that something is about to happen, to give the Activity a
     * chance to save state.
     *
     * @param outState a Bundle into which this Activity should save its state
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
         just have the View's thread save its state into our Bundle
        super.onSaveInstanceState(outState);
        mLunarThread.saveState(outState);
        Log.w(this.getClass().getName(), "SIS called");
    }
    public boolean onTouchEvent(MotionEvent event){
        int clickX = Math.round(event.getX()/10)*10;
        int clickY = Math.round(event.getY()/10)*10;

LunarView.xCo = clickX;
        LunarView.yCo = clickY;

return true;

}

Solution

As Greg suggests, the problem is getting the correct Context to retrieve resources.
An easy way to solve this problem is to pass the main activity as an argument to the Worker class constructor and save it as a private Context field. Something like this:

public class Worker{
  private Context mContext;
  public Worker (Context context) {
    mContext = context;
    Resources res = mContext.getResources();
     all the rest of your code
  }
}

You’ll use it in your main activity as:

Worker worker = new Worker(this);

Related Problems and Solutions