2

I know there are a few Android Timer posts, and I can't really see what I'm missing from them.

The user presses a button to begin the game, text is updated with the seconds that have passed, and, if the button is pressed after eight seconds, a congratulatory message is displayed.

public static class PlaceholderFragment extends Fragment {

    public static long startTime;
    public static int time;
    public static boolean buttonClicked1;
    public static boolean buttonClicked2;
    public static boolean win;
    public static TextView todd;
    public static TextView tim;
    public static Button bob;

    public PlaceholderFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);

        win = false;
        bob = (Button)rootView.findViewById(R.id.button);
        tim = (TextView)rootView.findViewById(R.id.message);

        todd = (TextView)rootView.findViewById(R.id.timer);
        startTime = System.currentTimeMillis();
        time = 0;
        buttonClicked1 = false;
        buttonClicked2 = false;

        bob.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View arg0) {
                if(!buttonClicked1){
                    buttonClicked1 = true;
                    bob.setText("Push Here");
                    play();
                }
                else if(buttonClicked1) //Has game started
                {
                    if(time>8)
                        buttonClicked2 = true;

                }                   
            }
        });

        return rootView;
    }

    public void play(){
        playThread paul = new playThread();
        paul.run();
    }

    public void winner(){
         tim.setText("Congratulations");
    }

    public boolean checkWin(){
        return buttonClicked2 ? true : false;
    }

    public void updateTime(){
        if((System.currentTimeMillis() - startTime) % 1000 > 0){
            startTime = System.currentTimeMillis();
            time++;
        }
        todd.setText(""+time);
    }

    private class playThread implements Runnable{
        public void run(){
            System.out.println("Thread running");
            while(!win){
                updateTime();
                win = checkWin();
                winner();
            }
        }
    }
}

}

I decided to implement Runnable instead of extending Thread for the playThread private class after reading this.

The game becomes unresponsive after hitting the start button, the text of which doesn't change to "Push Here".

I am, of course, a complete Android beginner, and I suspect the issue is with my implementation of a thread, but the problem may be elsewhere because I'm not too familiar with the programming style or conventions.

Thanks for looking this over!

Community
  • 1
  • 1
Nick
  • 581
  • 1
  • 7
  • 13

1 Answers1

0

Your playThread class, despite its name, does not create a new thread. It runs in the main GUI thread and contains a loop that hangs your app. Creating an instance of this class a calling its run method simply runs that code in the main thread. You should create a thread an run that instance in that separate thread.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • If he starts the thread on an actual seperate thread, he will get a `CalledFromWrongThreadException` in `winner()`. – EpicPandaForce Jul 22 '14 at 14:33
  • I thought the Runnable class, like a thread, ran separately, and would not cause the app to hang. How can I repeatedly update the time without a loop? – Nick Jul 22 '14 at 14:34
  • 2
    `Thread thread = new Thread(new playThread()); thread.start();` starts the Runnable on a seperate thread – EpicPandaForce Jul 22 '14 at 14:35
  • @Nick Runnable it an interface that you can pass to a Thread instance, which would run its `run` method in a new Thread when that thread is started. – Eran Jul 22 '14 at 14:35
  • I'd help more, but I ran into issues with this approach and drew out the timer onto the canvas of a SurfaceView directly rather than mess around with TextViews. As I said, even if you start the thread, the `winner()` will access the TextView from another Thread, and not the UI thread (this results in an `CalledFromWrongThreadException `). You can of course call `runOnUiThread(new Runnable() { winner(); });` but there's definitely a better approach than that, hence why I abandoned the text view for display in a use-case like this. (I was writing a game) – EpicPandaForce Jul 22 '14 at 14:39
  • Thanks guys, I'm trying the edits. I added some background about my original understanding of Runnable to the main post. – Nick Jul 22 '14 at 14:40
  • @Nick, Just to underscore what Eran already said, there is nothing magic about Runanble. It is _just_ an interface. A Runnable object is an object with a run() method. What you do with it is up to you. What some Thread object, t, does with it is, it calls the run() method in the new thread _after_ somebody creates the new thread by calling t.start(). – Solomon Slow Jul 22 '14 at 14:46
  • I fiddled with the code and moved winner() out of the thread and to the button onClickListener, where I relocated checkWin(). The only thing left in the playThread is "while(!win){updateTime()}". The only result seems to be that the button now changes to the text "Push Here" moments before crashing. – Nick Jul 22 '14 at 16:18