Android: Using the CountDownTimer class

In this article I go over the Android SDK CountDownTimer class. It’s easy to use and gives you the ability to count for projects like a workout timer. In this case we are extending that class so that we can access the methods we need to make it work.

Here is the code on GitHub.

Here is our SimpleCountDownTimer:

public class SimpleCountdownTimer extends CountDownTimer {
    public static int oneSecond = 1000;
    TextView textViewTimeLeftDisplay;

    public SimpleCountdownTimer(long millisInFuture, long countDownInterval,
                                TextView textViewTimeLeftDisplay) {

        super(millisInFuture, countDownInterval);

        this.textViewTimeLeftDisplay = textViewTimeLeftDisplay;
    }

    @Override
    public void onFinish() {
        textViewTimeLeftDisplay.setText("Finished");
    }

    @Override
    public void onTick(long millisUntilFinished) {
        textViewTimeLeftDisplay.setText(String.valueOf(millisUntilFinished / oneSecond));
    }
}

The extended timer class takes in the amount of time we want to count, the counting interval, and a textview that we will send status to. We update the text view every interval as well as when we are finished. There really isn’t much to it.

Here is our main activity:

public class MainActivity extends Activity {
    Spinner timerValueSpinner;
    Button startTimerButton;
    Button stopTimerButton;
    TextView statusTextView;
    SimpleCountdownTimer timer;
    String[] timeValues;
    Resources resourcePointer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        timerValueSpinner = (Spinner)this.findViewById(R.id.secondsSpinner);
        statusTextView = (TextView)this.findViewById(R.id.timerView);

        resourcePointer = getResources();
        timeValues = resourcePointer.getStringArray(R.array.seconds_list);

        //the button that will start the timer
        startTimerButton = (Button)this.findViewById(R.id.startButton);
        startTimerButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(timerValueSpinner.getSelectedItemPosition() > -1) {
                    int parsedSpinnerValue = 0;
                    parsedSpinnerValue = Integer.parseInt(
                            timeValues[timerValueSpinner.getSelectedItemPosition()]);

                    if (parsedSpinnerValue > 0) {
                        //if there is a timer already, end that before making a new one
                        if(timer != null) {
                            timer.cancel();
                        }

                        //initialize a new timer instance
                        timer = new SimpleCountdownTimer(parsedSpinnerValue
                                * SimpleCountdownTimer.oneSecond,
                                SimpleCountdownTimer.oneSecond,
                                statusTextView);

                        timer.start();
                    }
                }
            }
        });

        //the button that will stop the timer
        stopTimerButton = (Button)this.findViewById(R.id.stopButton);
        stopTimerButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(timer != null) {
                    timer.cancel();
                }
            }
        });
    }
}

In the main activity we do a lot of referencing to our interface. In the start timer button we extract a value from the spinner, convert it into an int, make sure any existing timer is stopped, and instantiate a new timer with the spinner value.

Posted in Android, Java | Tagged , , , | Comments

C#: Using the Background Worker to thread your application processing.

In this article I go over using the background worker control in C# .NET Framework (Visual Studio 2015). This control allows you to easily do processing intensive tasks without locking up your interface thread. I use this a lot in winforms applications where I expect code to take any amount of time that the user would notice the interface being locked up while processing. This control gives you the ability to send progress updates to the interface thread as well as cancel processing any any time.

The code for this example is on my GitHub here.

Here is the important code from the main form:

public enum CurrentStatus
{
    None,
    Reset,
    Loading,
    Cancelled,
    Success,
    Busy
}
        
//used throughout the form to track application status
CurrentStatus processingStatus = CurrentStatus.None;

/// <summary>
/// changes the interface based on current status (processingStatus)
/// </summary>
void setFormControlsBasedOnStatus()
{
    switch (processingStatus)
    {
        case CurrentStatus.None:
            break;
        case CurrentStatus.Reset:
            btnStartWorker.Enabled = true;
            btnStopWorker.Enabled = false;
            lblLoadingStatus.Visible = false;
            lblLoadingStatus.Text = "Loading...";
            pbLoadingGraphic.Visible = false;
            prgLoadingProgress.Value = 0;
            break;

        case CurrentStatus.Loading:
            btnStartWorker.Enabled = false;
            btnStopWorker.Enabled = true;
            lblLoadingStatus.Visible = true;
            lblLoadingStatus.Text = "Loading...";
            pbLoadingGraphic.Visible = true;
            prgLoadingProgress.Value = 0;
            break;

        case CurrentStatus.Cancelled:
            btnStartWorker.Enabled = true;
            btnStopWorker.Enabled = false;
            lblLoadingStatus.Visible = true;
            lblLoadingStatus.Text = "Cancelled";
            pbLoadingGraphic.Visible = false;
            prgLoadingProgress.Value = 0;
            break;

        case CurrentStatus.Success:
            btnStartWorker.Enabled = true;
            btnStopWorker.Enabled = false;
            lblLoadingStatus.Visible = true;
            lblLoadingStatus.Text = "Success!";
            pbLoadingGraphic.Visible = false;
            prgLoadingProgress.Value = 0;
            break;

        case CurrentStatus.Busy:
            btnStartWorker.Enabled = true;
            btnStopWorker.Enabled = false;
            lblLoadingStatus.Visible = true;
            lblLoadingStatus.Text = "The worker is busy.";
            pbLoadingGraphic.Visible = false;
            prgLoadingProgress.Value = 0;
            break;

        default:
            break;
    }
}

/// <summary>
/// see if the user wants to cancel the background worker
/// </summary>
/// <param name="worker">the worker</param>
/// <param name="e">worker status</param>
/// <returns>used to tell the caller to exit or not</returns>
bool isWorkerBeingCancelled(BackgroundWorker worker, DoWorkEventArgs e)
{
    bool returnValue = false;

    if (worker.CancellationPending == true)
    {
        e.Cancel = true;
        returnValue = true;
        processingStatus = CurrentStatus.Cancelled;
    }

    return returnValue;
}

/// <summary>
/// background worker processing step
/// </summary>
/// <param name="sender">worker instance</param>
/// <param name="e">current status</param>
private void bwInstance_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;

    //mimic work and update or cancel the worker as we go
    if (isWorkerBeingCancelled(worker, e)) return; //check for user cancel
    worker.ReportProgress(20);
    System.Threading.Thread.Sleep(250);

    //mimic work and update or cancel the worker as we go
    if (isWorkerBeingCancelled(worker, e)) return; //check for user cancel
    worker.ReportProgress(40);
    System.Threading.Thread.Sleep(250);

    //mimic work and update or cancel the worker as we go
    if (isWorkerBeingCancelled(worker, e)) return; //check for user cancel
    worker.ReportProgress(60);
    System.Threading.Thread.Sleep(250);

    //mimic work and update or cancel the worker as we go
    if (isWorkerBeingCancelled(worker, e)) return; //check for user cancel
    worker.ReportProgress(80);
    System.Threading.Thread.Sleep(250);

    //mimic work and update or cancel the worker as we go
    if (isWorkerBeingCancelled(worker, e)) return; //check for user cancel
    worker.ReportProgress(100);
    System.Threading.Thread.Sleep(250);

    processingStatus = CurrentStatus.Success;
}

/// <summary>
/// updates any progress controls visually
/// </summary>
/// <param name="sender">current instance</param>
/// <param name="e">passed progress</param>
private void bwInstance_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    prgLoadingProgress.Value = e.ProgressPercentage;
}

/// <summary>
/// happens once the background worker is completed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void bwInstance_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    setFormControlsBasedOnStatus();
}

/// <summary>
/// a button to start processing
/// </summary>
private void btnStartWorker_Click(object sender, EventArgs e)
{
    if (bwInstance.IsBusy == false)
    {
        processingStatus = CurrentStatus.Loading;
        setFormControlsBasedOnStatus();
        bwInstance.RunWorkerAsync();
    }
    else
    {
        processingStatus = CurrentStatus.Busy;
        setFormControlsBasedOnStatus();
    }
}

/// <summary>
/// a button to stop processing
/// </summary>
private void btnStopWorker_Click(object sender, EventArgs e)
{
    bwInstance.CancelAsync();
}

I made a status enumeration with a form-level variable that holds the current processing status. I also have a function to update the interface based on that status enum. The background worker is called to see if is busy, if not, the worker is started. Throughout processing, we check to see if the user cancelled the work and also update the progress control by pushing a numeric value (0-100 to match our progress control) through the worker into the interface thread. When the cancel button is clicked, it sets a value in the background worker that we can track to stop processing as needed. I have a function that is called throughout processing that will break out of the processing function and set our enum status variable telling the system that processing was cancelled.

Posted in C# | Tagged , , , , , | Comments

Android: Working with Preferences and Settings

In this article I go over using the built-in Android settings and preference system. I have a settings class as well as an activity that manages user input. A spinner is assigned the task of letting the user turn on or off a vibration feature. When the application is started again, the setting is accessed and assigned to the spinner. It also enables or disables the vibrator based on our saved preference.

The code is available on GitHub here.

Here is our Settings class:

public class Settings {
    public static final String PREFS_NAME = "twoc_settings_example";
    public static final String KEY_SETTINGS_AVAILABLE = "settingsavailable";

    //your custom settings in the application
    public static final String KEY_STATE_VIBRATION = "vibrationstate";

    //the object used to access settings for this application stored in a predefined setting area
    SharedPreferences prefAccessor;

    public Settings(Context parentContext) {
        prefAccessor = parentContext.getSharedPreferences(PREFS_NAME, 0);

        //this code should execute only one when the application is first executed once installed
        if(prefAccessor.contains(KEY_SETTINGS_AVAILABLE)) {
            SharedPreferences.Editor editor = prefAccessor.edit();

            //make it so that we won't need to run this initialization code again
            editor.putString(KEY_SETTINGS_AVAILABLE, "true");

            //make sure preferences exist, if they don't initialize them with defaults
            if(prefAccessor.contains(KEY_STATE_VIBRATION)) {
                editor.putString(KEY_STATE_VIBRATION, "On");
            }

            editor.apply();
        }
    }

    /**
     * return an application setting
     * use the public static KEY_.... constants of this class as the function parameter
     *
     * @param settingKeyName key name from one of the internal constants
     * @return the value or an empty string if not found
     */
    public String getSettingValue(String settingKeyName) {
        return prefAccessor.getString(settingKeyName, "");
    }

    /**
     * set one of the application settings
     * use the public static KEY_.... constants of this class
     * as the function parameter (settingKeyName)
     *
     * @param settingKeyName key name from one of the internal constants
     * @param valueToInsert value to save into that setting
     */
    public void setSettingValue(String settingKeyName, String valueToInsert) {
        SharedPreferences.Editor editor = prefAccessor.edit();
        editor.putString(settingKeyName, valueToInsert);
        editor.apply();
    }

    /***
     * a function to quickly get the vibration setting value
     *
     * @return the setting value
     */
    public boolean isVibrationOn() {
        boolean returnValue = false;
        if(prefAccessor.getString(KEY_STATE_VIBRATION, "").equals("On")) {
            returnValue = true;
        }
        return returnValue;
    }
}

In there we deal with the first-run initialization of the preferences for our application and any defaults we want to define. I also have two generalized functions that allow you to save or get a setting. There is a function that allows us quick access to the vibrator on/off setting that we use in the Activity.

Here is our main activity:

public class MainActivity extends Activity {
    Resources resourcePointer;
    Settings settings;
    String[] arrayOnOff;
    Spinner vibrationSpinner;
    Button quitButton;
    Activity thisActivity;

    Vibrator vibrator;
    boolean vibrationOn = true;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        thisActivity = this;

        //instantiate our custom settings object
        settings = new Settings(this);

        //initialize a variable that we can use to access project resources
        resourcePointer = getResources();

        //fetch needed array lists for the options controls
        arrayOnOff = resourcePointer.getStringArray(R.array.array_onoff);

        vibrationSpinner = (Spinner)findViewById(R.id.options_vibration_spinner);
        vibrationSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onNothingSelected(AdapterView<?> parentView) {}
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                settings.setSettingValue(Settings.KEY_STATE_VIBRATION, arrayOnOff[position]);
                vibrationOn = settings.isVibrationOn();
            }
        });

        //create a handler for the quit button
        quitButton = (Button) findViewById(R.id.main_btn_quit);
        quitButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View arg0) {
                thisActivity.finish();
            }
        });
    }

    /***
     * this happens after onCreate and after a restart
     */
    @Override
    public void onStart() {
        super.onStart();

        //attempt to select a previously saved setting if needed
        String currentVibrationSetting = settings.getSettingValue(Settings.KEY_STATE_VIBRATION);
        if(!currentVibrationSetting.trim().equals("")) {
            int spinnerPosition = getSpinnerItemPosition(vibrationSpinner, currentVibrationSetting);
            if(spinnerPosition > -1) {
                vibrationSpinner.setSelection(spinnerPosition);
            }
        }

        //initialize the vibrator service if necessary
        vibrationOn = settings.isVibrationOn();
        if(vibrationOn) {
            //use the vibration feature of the device if desired by the user
            vibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
        }
    }

    /***
     * attempt to find an item in a spinner based on the textual value
     *
     * @param spinner control to search
     * @param stringToFind string to find
     * @return -1 or the item index
     */
    int getSpinnerItemPosition(Spinner spinner, String stringToFind) {
        int index = -1;
        for (int i = 0; i < spinner.getCount(); i++) {
            if (spinner.getItemAtPosition(i).equals(stringToFind)) {
                index = i;
                break;
            }
        }
        return index;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if(vibrationOn && vibrator != null) {
                    vibrator.vibrate(100);
                } else if (vibrationOn) {
                    //(re)initialize the vibrator object
                    vibrator = (Vibrator)getSystemService(VIBRATOR_SERVICE);
                    vibrator.vibrate(100);
                }
                break;
        }

        return true;
    }
}

In this case we deal setting up the user interface, handing the setting being changed, and managing the vibrator based on that setting.

Posted in Android, Java | Tagged , , , , , | Comments