3

I'm writing a Android Whack-a-mole game. As we all know, the moles will pop up frequently on the UI and the timer text view is changed every second. So I used handlers for all of these works. I was told to use handlers instead of java.util.Timer in this question.

However, It didn't work the way I wanted it to. I mean it kind of worked but the timer text view's text changed irrationally. When I checked the logcat it said I'm doing too much work on the main thread.

Back then, when I was developing winforms programs, this problem never occurs. I was thinking about putting those handlers on another thread but as I know only the UI thread can access UI stuff, right?

Here is my countdown class:

package com.whackanandroid;

import android.os.Handler;
import android.widget.TextView;

public class CountDown {
    private Handler handler;
    private int timeLeft;
    private TextView textView;
    private boolean paused;
    private CountDownListener listener;

    private Runnable countDownTask = new Runnable () {
        @Override
        public void run() {
            if (!paused) {
                timeLeft--;
                displayTime ();
                handler.postDelayed (this, 100);
                if (timeLeft == 0) {
                    pauseCountDown ();
                    if (listener != null)
                        listener.onCountDownFinished ();
                }
            }
        }
    };

    private void displayTime () {
        textView.setText (Integer.toString (timeLeft / 10));
    }

    public void pauseCountDown () {
        paused = true;
    }

    public void startCountDown () {
        paused = false;
        handler.post (countDownTask);
    }

    public void setCountDownListener (CountDownListener listener) {
        this.listener = listener;
    }

    public CountDown (TextView tv) {
        textView = tv;
        timeLeft = 600;
        handler = new Handler ();
    }
}

And here is my phone class (the "mole")

package com.whackanandroid;

import android.os.Handler;
import android.view.View;
import android.widget.ImageView;

import java.util.Random;

public class Phone {
    private ImageView image;
    private Handler handler;
    private Random random;
    private State state;
    private boolean paused;

    private Runnable appearTask = new Runnable () {
        @Override
        public void run() {
            if (!paused) {
                if (random.nextInt (3) < 2) {
                    setState (State.ANDROID);
                    Game.getInstance ().addScore (10);
                } else {
                    setState (State.APPLE);
                    Game.getInstance ().addScore (-5);
                }
                handler.postDelayed (disapperTask, random.nextInt (1000) + 700);
            }
        }
    };

    private Runnable disapperTask = new Runnable () {
        @Override
        public void run() {
            if (!paused) {
                setState (State.NONE);
                handler.postDelayed (appearTask, random.nextInt (2000) + 1000);
            }
        }
    };


    private View.OnClickListener imageOnClick = new View.OnClickListener () {
        @Override
        public void onClick(View v) {
            //TODO add OnClickListener
        }
    };

    public void setState (State value) {
        state = value;
        switch (state) {
            case NONE:
                image.setImageResource (R.drawable.phone);
                break;
            case ANDROID:
                image.setImageResource (R.drawable.androidphone);
                break;
            case APPLE:
                image.setImageResource (R.drawable.applephone);
                break;
        }
    }

    public State getState () {
        return state;
    }

    public void stopTimers () {
        paused = true;
    }

    public void startTimers () {
        paused = false;
        if (getState () == State.NONE) {
            handler.postDelayed (appearTask, random.nextInt (2000) + 1000);
        } else {
            handler.postDelayed (disapperTask, random.nextInt (1000) + 700);
        }
    }

    public Phone (ImageView view, Random r) {
        view.setOnClickListener (imageOnClick);
        image = view;
        random = r;
        handler = new Handler ();
        image.setImageResource (R.drawable.phone);
    }
}

I think my code just looks horrible. Hope you don't mind. If you need any more code, please tell me at once.

Community
  • 1
  • 1
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • What is the "Working" that you do? you should put any heavy work in async task or worker thread. – Liran Peretz Jul 30 '15 at 08:48
  • `Handler`s I guess. I have too many of them on the main thread, maybe? – Sweeper Jul 30 '15 at 08:49
  • You can post some code? – Liran Peretz Jul 30 '15 at 08:50
  • For timers, maintain a separate thread. For timer view, use a SurfaceView. The surfaceview allows any thread to touch it. So a timer specific thread keeps on updating SurfaceView at specific interval. – Harish Sridharan Jul 30 '15 at 08:53
  • But I was told to use Handlers though. For timers, I can't change the intervals randomly. see the link in my question @HarishSridharan – Sweeper Jul 30 '15 at 08:56
  • Question Edited @LiranPeretz – Sweeper Jul 30 '15 at 08:56
  • it's look like that you work always on the main thread and the "work" doesn't seem heavy, you have a listener that invoked th onCountDownFinished method, try to see if there you have an heavy work... – Liran Peretz Jul 30 '15 at 08:58
  • @LiranPeretz I have 8 `Phone` objects though. Also the onCountDownFinished method just calls another empty method that hasn't been completed yet. – Sweeper Jul 30 '15 at 09:01
  • 2
    ok, so i suggest to use TraceView tool for figure out the heavy methods that cause this problem. link to trace view documentation: http://developer.android.com/tools/debugging/debugging-tracing.html – Liran Peretz Jul 30 '15 at 09:04
  • OK I'll try that. @LiranPeretz – Sweeper Jul 30 '15 at 09:05
  • 1
    Why do I get 2 upvotes? Is my question really that good? @LiranPeretz – Sweeper Jul 30 '15 at 09:26
  • @Sweeper your code is not bad and you showed some effort before asking which makes it a good question. – Dmitry Zaytsev Jul 30 '15 at 09:28
  • @Sweeper please, analyze results of profiling and then update your question (if you won't find the answer by yourself) – Dmitry Zaytsev Jul 30 '15 at 09:30
  • I just run the app on my phone (not pressing the start button in Android Studio) and it doesn't happen! Should I delete the question now? – Sweeper Jul 30 '15 at 09:32

0 Answers0