Search code examples
javaandroidtimertimertasksettext

Repeating Event Crashing App


I need some help with an Android app I'm developing. I have tons of experience with C, perl, and assembly but I'm a complete Java noob.

In a nutshell, I'm writing an app that will display a running clock. I understand that there are built in clock widgets but I'd prefer to accomplish this with a TextView object that I update once per second. However, when I set up a repeating event and try to use the setText method, my app crashed. Something about calling setText from outside the thread that created it.

I searched a little and saw some suggestions about using handlers but I wasn't successful with that approach. Can someone point out what I'm doing wrong or suggest a better approach?

My code is below. I'm using Android Studio 0.8.9 and running the app on my LG G2.

Thanks in advance for any help you can provide.

package com.joshrocks.betclock;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

import android.graphics.Typeface;
import android.widget.TextClock;
import android.widget.TextView;

import java.util.Calendar;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;


public class BET_Clock extends Activity {

    //TextView and TextClock definitions
    TextView lab_GMT;
    TextView lab_LCL;
    TextView lab_BET;
    TextView lab_BJD;
    TextView Day_LCL;
    TextView Slash_LCL;
    TextClock time_LCL;
    TextView Day_GMT;
    TextView Slash_GMT;
    TextClock time_GMT;

    //Calendar declarations
    Calendar GMT_Calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    Calendar LCL_Calendar = Calendar.getInstance();

    //Call GMT and LCL Day of the year
    int GMT_dayOfYear = GMT_Calendar.get(Calendar.DAY_OF_YEAR);
    int LCL_dayOfYear = LCL_Calendar.get(Calendar.DAY_OF_YEAR);


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bet__clock);
        Typeface dot_matrix=Typeface.createFromAsset(getAssets(),"fonts/led_counter-7.ttf");

        //Label font definitions
        lab_LCL = (TextView) findViewById(R.id.Label_LCL);
        lab_LCL.setTypeface(dot_matrix);
        lab_GMT = (TextView) findViewById(R.id.Label_GMT);
        lab_GMT.setTypeface(dot_matrix);
        lab_BET = (TextView) findViewById(R.id.Label_BET);
        lab_BET.setTypeface(dot_matrix);
        lab_BJD = (TextView) findViewById(R.id.Label_BJD);
        lab_BJD.setTypeface(dot_matrix);

        //GMT Time field font definitions
        Day_GMT = (TextView) findViewById(R.id.Day_GMT);
        Day_GMT.setTypeface(dot_matrix);
        Day_GMT.setText(String.valueOf(GMT_dayOfYear));
        Slash_GMT = (TextView) findViewById(R.id.Slash_GMT);
        Slash_GMT.setTypeface(dot_matrix);
        time_GMT = (TextClock) findViewById(R.id.Time_GMT);
        time_GMT.setTypeface(dot_matrix);

        //LCL Time field font definitions
        Day_LCL = (TextView) findViewById(R.id.Day_LCL);
        Day_LCL.setTypeface(dot_matrix);
        Day_LCL.setText(String.valueOf(LCL_dayOfYear));
        Slash_LCL = (TextView) findViewById(R.id.Slash_LCL);
        Slash_LCL.setTypeface(dot_matrix);
        time_LCL = (TextClock) findViewById(R.id.Time_LCL);
        time_LCL.setTypeface(dot_matrix);


         Timer timer = new Timer();
         timer.scheduleAtFixedRate(new TimerTask() {

            @Override
            public void run() {
                UpdateTimes();
            }

         },0, 1000);

    }//end OnCreate


    public void UpdateTimes() {
        LCL_dayOfYear += 1;
        Day_LCL.setText(String.valueOf(LCL_dayOfYear));
    }//end UpdateTimes


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.bet__clock, menu);
        return true;
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

}

Solution

  • Try this.

    Timer timer = new Timer();
             timer.scheduleAtFixedRate(new TimerTask() {
    
                @Override
                public void run() {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                           UpdateTimes();
                        }
                    });
                }
    
             },0, 1000);
    

    You need to call runOnUiThread in order to change view objects from other threads than the main UI thread.