0

I'm learning Android and java while building a timer application for myself.
Referencing an old thread, Android - Controlling a task with Timer and TimerTask? I am trying to create the Runnable method to count down my timer.
The basic java issue I'm stuck on is what to class do I attach the postDelayed() call?

My activity is called TimerButtons for now, and I thought this would work:

    package com.TimerButtons;

    import android.app.Activity;
    import android.graphics.Color;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuffColorFilter;
    import android.graphics.drawable.Drawable;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;

    public class TimerButtons extends Activity {

        private TextView mDisplayTime;

        private Button mButtonStart;
        private Button mButtonStop;

        private int timeTenths = 0;

        private Drawable d;
        private PorterDuffColorFilter filter;

        // capture our View elements
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);

            filter = new PorterDuffColorFilter(Color.DKGRAY, PorterDuff.Mode.SRC_ATOP);  
            d = findViewById(R.id.buttonStart).getBackground(); d.setColorFilter(filter);
            d = findViewById(R.id.buttonStop).getBackground(); d.setColorFilter(filter);

            mDisplayTime = (TextView) findViewById(R.id.displayTime);

            mButtonStart = (Button) findViewById(R.id.buttonStart);
            mButtonStop = (Button) findViewById(R.id.buttonStop);


            // add click listeners to the buttons
            mButtonStart.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                                new Thread(r).start();
                }
            });

            mButtonStop.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    timeTenths = 0;
                    updateDisplay();
                    updateSetting();
                }
            });

            // display the current time
            updateDisplay();

        }

        // runtime methods below here
        // updates the time we display in the TextView
        private void updateDisplay() {
            mDisplayTime.setText(
                    String.valueOf(((float)timeTenths)/10)
            );
        }

        private void updateSetting() {
            mTensDigit.setText(String.valueOf(timeTenths/100));
            mOnesDigit.setText(String.valueOf((timeTenths%100)/10));
            mTenthsDigit.setText(String.valueOf(timeTenths%10));
        }

        Runnable r = new Runnable()
        {
            public void run() 
            {
                if (timeTenths >= 1)
                {
                    timeTenths -= 1;
                    if (timeTenths != 0)
                        mDisplayTime.postDelayed(this, 100);
                    updateDisplay();
                }
            }
        };

    }  

I get the error: The method postDelayed(new Runnable(){}, int) is undefined for the type TimerButtons on the commented line.

Thanks for any noob guidance!
Dave

Community
  • 1
  • 1
DBell
  • 61
  • 1
  • 1
  • 6

2 Answers2

0

I think you have the handler class to complete your task.

you have approach it differently...

I don't know what you are really want to do with this class but this is one implementation.

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

import com.tobee.sms.R;

import android.app.Activity;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class TimerButtons extends Activity {

    private TextView mDisplayTime;

    private Button mButtonStart;
    private Button mButtonStop;

    //private int timeTenths = 0;

    private Drawable d;
    private PorterDuffColorFilter filter;
    
    private TinyTimer myTimer;
    
    // capture our View elements
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        filter = new PorterDuffColorFilter(Color.DKGRAY, PorterDuff.Mode.SRC_ATOP); 
        
        d = findViewById(R.id.buttonStart).getBackground(); d.setColorFilter(filter);
        d = findViewById(R.id.buttonStop).getBackground(); d.setColorFilter(filter);
        
        mDisplayTime = (TextView) findViewById(R.id.displayTime);
        
        mButtonStart = (Button) findViewById(R.id.buttonStart);
        mButtonStop = (Button) findViewById(R.id.buttonStop);
        
       

        // add click listeners to the buttons
        mButtonStart.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                //new Thread(r).start();
                myTimer.startTimer(1000, mDisplayTime, mTensDigit, mOnesDigit, mTenthsDigit);
            }
        });

        mButtonStop.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                //timeTenths = 0;
                //updateDisplay();
                updateSetting();
            }
        });
        
        myTimer = new TinyTimer();
        
        // display the current time
        //updateDisplay();

    }

    // runtime methods below here
    // updates the time we display in the TextView
    private void updateDisplay() {
        //mDisplayTime.setText(
        //        String.valueOf(((float)timeTenths)/10)
        //);
    }

    private void updateSetting() {
        //mTensDigit.setText(String.valueOf(timeTenths/100));
        //mOnesDigit.setText(String.valueOf((timeTenths%100)/10));
        //mTenthsDigit.setText(String.valueOf(timeTenths%10));
        
        
    }

    //Runnable r = new Runnable()
    //{
    //    public void run() 
    //    {
    //        if (timeTenths >= 1)
    //        {
    //            timeTenths -= 1;
    //            if (timeTenths != 0)
    //                mDisplayTime.postDelayed(this, 100);
    //            updateDisplay();
    //        }
    //    }
    //};
    
   
    public class TinyTimer {

        private Handler _handler;
        
        private long _startTime = 0;
        private long _millis;
        
        private long _delayMillis;
        
        private TextView mDisplayTime;
        private TextView mTensDigit;
        private TextView mOnesDigit;
        private TextView mTenthsDigit;
        
        private String _format = String.format("%%0%dd", 2); 
        
        private int timeTenths = 0;
        
        public TinyTimer(){
            _handler = new Handler();
        }

        public void startTimer
        (long delayMillis,TextView DisplayTime, TextView TensDigit, TextView OnesDigit, TextView TenthsDigit){
            mDisplayTime = (TextView) DisplayTime;
            mTensDigit = (TextView) TensDigit;
            mOnesDigit = (TextView) OnesDigit;
            mTenthsDigit = (TextView) TenthsDigit;
            
            _delayMillis = delayMillis;
            _startTime = SystemClock.elapsedRealtime();
            _handler.removeCallbacks(updateTimerTask);

            updateTimerTask.run();
        }
        
        public void stopTimer(){
            _handler.removeCallbacks(updateTimerTask);
        }
        
        public void pauseTimer(){
            _handler.removeCallbacks(updateTimerTask);
        }
        
        public void unpauseTimer(){
            if(_startTime != 0){
                updateTimerTask.run();          
            }
        }
        
        private Runnable updateTimerTask = new Runnable() {
            
            @Override
            public void run() {
                final long start = _startTime;
                _millis = SystemClock.elapsedRealtime() - start;
                
                
                if (timeTenths >= 1)
                {
                    timeTenths -= 1;
                    if (timeTenths != 0)
                        mDisplayTime.postDelayed(this, 100);
                    
                    mDisplayTime.setText(String.valueOf(((float)timeTenths)/10));
                    mTensDigit.setText(String.valueOf(timeTenths/100));
                    mOnesDigit.setText(String.valueOf((timeTenths%100)/10));
                    mTenthsDigit.setText(String.valueOf(timeTenths%10));
                }
                _handler.postDelayed(updateTimerTask, _delayMillis);
            }
        };
            
        public long getElapsedtime(){
            return _millis;
        }
        
        public String getMillis(){
            return String.format(_format, _millis % 1000);
        }
        
        
}  

The class i implemented is just a concept. I haven't test but compile class.

tommybee
  • 2,409
  • 1
  • 20
  • 23
0

If TimerButtons is your Activity, that should work. Try this:

TimerButtons.this.postDelayed(this, 1000);

EDIT (for posterity): I was initially wrong: postDelayed is defined on a View, not a Context. Use

mDisplayTime.postDelayed(this, 1000);
Femi
  • 64,273
  • 8
  • 118
  • 148
  • Just tried that, but same error. The old thread spoke of creating a handler, but I'm lost there, as well. – DBell May 07 '11 at 16:22
  • Put up a code sample showing the surrounding method: hard to tell what exactly is going on if that doesn't work. – Femi May 07 '11 at 16:28
  • Hate to post the entire code; maybe this will help: The code I posted originally is an entire method, the last one created after (outside) the end of the onCreate block. Dave – DBell May 07 '11 at 16:31
  • @Femi and others: Edited post to include the whole app. I deleted a lot of button coloring, etc., but I believe the entire structure represents what I am trying to do. Dave – DBell May 07 '11 at 17:09
  • AH. You need to do the `postDelayed` call on a view within the activity. Try `mDisplayTime.postDelayed`. – Femi May 07 '11 at 17:23
  • And: if you only want `updateDisplay` to be run when the timer counts down you probably want to put a `return` statement as part of the `if` block, otherwise `updateDisplay` gets called every time. Your use of a Runnable for that is a little confusing. Might be worthwhile to look at http://developer.android.com/reference/android/os/CountDownTimer.html which is pretty much designed for what you're trying to do and handles the thread synchronization for you. – Femi May 07 '11 at 17:25
  • @Femi - Wow! That CountDownTimer() is too simple! Looks like time for a redesign. I used a Runnable because that was the only trick I'd seen, and the logic seemed fine. I'd kinda like to make the original method work first, so I understand better what I am doing. Could you please expand a little on your correction? I believe I do want updateDisplay() called each time (every 100 AS it is counting down)? I have to declare mDisplayTime first, don't I? (D'oh - did that) Thanks!! Dave – DBell May 07 '11 at 17:46
  • Edited to show latest code. No errors (thanks!), but doesn't count down. Am I missing a Start() or something? Dave – DBell May 07 '11 at 17:51
  • The correction is that (I was initially wrong): `postDelayed` is defined on a `View`, not on a `Context`. However all Views in the activity use the Activity's main thread. So you just need to reference any View in that Activity and you can `postDelayed` to the Activity's main thread. In general if you want to post to the Activity's main thread without referencing a View I usually use a Handler (see http://developer.android.com/reference/android/os/Handler.html) – Femi May 07 '11 at 17:51
  • Of COURSE I need a startup! I forgot it in the mButtonStart initialization. Can I just move the entire method declaration into the mButtonStart.setOnClickListener() block? – DBell May 07 '11 at 18:04
  • Should be able to put `new Thread(r).start();` at the end of `onCreate()`. – Femi May 07 '11 at 18:06
  • Wouldn't I put that in the listener for buttonStart? I don't want the thread to start when the app loads, but after I set the timer digits and hit Start... – DBell May 07 '11 at 18:21
  • Ah, yes: if you're planning to start it when you hit the button then it should be in the `onClick`. – Femi May 07 '11 at 18:24
  • Almost there!! I put new Thread(r).start(); at the end of the buttonStart listener, and it works - until it counts to zero. Then I get a Force Close. – DBell May 07 '11 at 18:25
  • Actually, I get the Force Close after only a couple of second of countdown, not at the end. First try was only 2 seconds, so it seemed like it was done when it crashed. Tried again with 10 seconds set, and it crashed around 8.x seconds on the clock. – DBell May 07 '11 at 18:34