Search code examples
androidmultithreadingrunnable

How To Convert extends Thread Class to Implement Runnable


I found some sample code online for creating a puzzle and I noticed that they have a Thread class that extends Thread and does things such as monitor the state of the puzzle and even sets properties of the surface view that is used for the puzzle.

I want to move this code into Run() by implementing Runnable. I have read that implementing Runnable is better than extending Thread, but I have no idea of how. Below is the class, that is called from a custom surface view. I want to instead implement Runnable in this surface view class (I think this is good). Thanks in advance.

public class ThreadHelper extends Thread {

    private SurfaceHolder mHolder;
    private PuzzleSurface mPuzzleSurface;
    private ThreadHelper mThread;

    private int gameState;
    private int puzzleSurfaceWidth = 1;
    private int puzzleSurfaceHeight = 1;
    public static final int STATE_PAUSE = 1;
    public static final int STATE_RUNNING = 2;
    private boolean isRunning = false;

    public ThreadHelper(SurfaceHolder holder, PuzzleSurface puzzleSurface) {
        mHolder = holder;
        mPuzzleSurface = puzzleSurface;
    }

    /**
     * Return running thread
     * @return
     */
    public ThreadHelper getThread() {
        return mThread;
    }

    /**
     * Stop running thread
     */
    public void destroy() {
        synchronized (mPuzzleSurface) {
            if (isRunning) {
                isRunning = false;
            }

            if (mThread != null) {
                mThread.interrupt();
                mThread = null;
            }
        }
    }

    /**
     * Method pauses game state
     */
    public void pause() {
        synchronized (mPuzzleSurface) {
            if (gameState == STATE_RUNNING) {
                setState(STATE_PAUSE);
            }
        }
    }

    /**
     * Method sets game state to running
     */
    public void unpause() {
        setState(STATE_RUNNING);
    }

    /**
     * Method is used to set the game state to either paused (1)
     * or running (2) states
     * @param stateToSet
     */
    public void setState(int stateToSet) {
        synchronized (mPuzzleSurface) {
            // TODO Message Handling
        }
    }

    /**
     *  Called to retrieve per-instance state from an activity 
     *  before being killed
     * @param outState
     * @return outState instance
     */
    public Bundle saveState(Bundle outState) {
        synchronized (mPuzzleSurface) {
            if (outState != null) {

            }
        }
        return outState;
    }

    /**
     * Called to set the size of the surfaceView
     * @param width
     * @param height
     */
    public void setSurfaceSize(int width, int height) {
        // synchronized to make sure these all change atomically
        synchronized (mPuzzleSurface) {
            puzzleSurfaceWidth = width;
            puzzleSurfaceHeight = height;
        }
    }

    /* (non-Javadoc)
     * @see java.lang.Thread#getState()
     */
    @Override
    public State getState() {
        // TODO Auto-generated method stub
        return super.getState();
    }

    /**
     * Method used to set running state of thread
     * @param run
     */
    public void setRunning(boolean run) {
        isRunning = run;
    }

    /* (non-Javadoc)
     * @see java.lang.Thread#run()
     * Calls the run() method of the Runnable object the 
     * receiver holds
     */
    @SuppressLint("WrongCall")
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while (isRunning) {
            Canvas c = null;
            try {
                c = mHolder.lockCanvas(null);
                synchronized (mHolder) {
                    mPuzzleSurface.onDraw(c);
                }
            } finally {
                if (c != null) {
                    mHolder.unlockCanvasAndPost(c);
                }
            }

        }
        super.run();
    }

}

Solution

  • In ThreadHelper.java change:

    public class ThreadHelper extends Thread {
    

    to:

    public class ThreadHelper implements Runnable {
    

    Then in places where you create and start a ThreadHelper, change all code that looks more or less like this:

    ThreadHelper threadHelper = new ThreadHelper(holder, puzzleSurface);
    threadHelper.start();
    

    to this:

    ThreadHelper threadHelper = new ThreadHelper(holder, puzzleSurface);
    Thread thread = new Thread(threadHelper);
    thread.start();
    

    That should do the trick!