2

I have a small app that calculates the time until a specified date and time. It works well.

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.widget.DigitalClock;
import android.widget.TextView;

public class Day2GoActivity extends Activity {
private TextView tvWeeks, tvDays, tvHours, tvMinutes, tvSeconds, timeUntil;


public Date curDateTime = new Date();
public Calendar today = Calendar.getInstance();
public Calendar leaving = Calendar.getInstance();
protected SimpleDateFormat sdf = new SimpleDateFormat("E dd-MMM-yyyy HH:mm");

protected Handler h = new Handler();
protected Runnable r = new Runnable() {
    public void run() {
        afficher();
    }
};

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    tvDays = (TextView) findViewById(R.id.tvDays);
    timeUntil = (TextView) findViewById(R.id.timeUntil);
    tvWeeks = (TextView) findViewById(R.id.tvWeeks);
    tvHours = (TextView) findViewById(R.id.tvHours);
    tvMinutes = (TextView) findViewById(R.id.tvMinutes);
    tvSeconds = (TextView) findViewById(R.id.tvSeconds);
}

@Override
protected void onResume() {
    super.onResume();
    Log.i("TAG", "Resuming");
    SharedPreferences sharedPreferences = getSharedPreferences("preferences", MODE_PRIVATE);
    Log.i("MyActvity", "Year = " + sharedPreferences.getInt("year", Calendar.YEAR));

    leaving.set(sharedPreferences.getInt("year", Calendar.YEAR), sharedPreferences.getInt("month", Calendar.MONTH),
            sharedPreferences.getInt("dayOfMonth", Calendar.DAY_OF_MONTH), sharedPreferences.getInt("hour", Calendar.HOUR_OF_DAY),
            sharedPreferences.getInt("minute", Calendar.MINUTE));
    timeUntil.setText("Time until: " + sdf.format(leaving.getTime()));
    r.run();
    Log.w("TAG", "Resumed");

}

private void afficher() {
    today = Calendar.getInstance();
    long millisToGo = leaving.getTimeInMillis() - today.getTimeInMillis();
    long seconds2go = TimeUnit.MILLISECONDS.toSeconds(millisToGo);
    tvSeconds.setText(String.format("%,d seconds", seconds2go));
    long minutes2go = TimeUnit.MILLISECONDS.toMinutes(millisToGo);
    tvMinutes.setText(String.format("%,d minutes", minutes2go));
    long hours2go = TimeUnit.MILLISECONDS.toHours(millisToGo);
    tvHours.setText(String.format("%d hours", hours2go));
    tvDays.setText(String.format("%d days %d hours", (int) hours2go / 24, hours2go % 24));
    long days2go = TimeUnit.MILLISECONDS.toDays(millisToGo);
    tvWeeks.setText(String.format("%d weeks %d days", (int) days2go / 7, days2go % 7));
    h.postDelayed(r, 1000);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    Intent myIntent = new Intent(getApplicationContext(), editDate.class);
    startActivity(myIntent);
    return true;
}

I have an issue, however, when the user changes the date and time. I have a second Activity which, as you can see is called in the onCreateOptionsMenu. It also works fine.

import java.util.Calendar;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.DatePicker;
import android.widget.TimePicker;

public class editDate extends Activity {

protected DatePicker dp1;
protected TimePicker tp1;
protected Calendar c;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.edit);
    dp1 = (DatePicker) findViewById(R.id.datePicker1);
    tp1 = (TimePicker) findViewById(R.id.timePicker1);
    tp1.setIs24HourView(true);
    LoadPreferences();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    SavePreferences();
}

private void SavePreferences() {
    SharedPreferences sharedPreferences = this.getSharedPreferences("preferences", MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPreferences.edit();

    editor.putInt("year", dp1.getYear());
    editor.putInt("month", dp1.getMonth());
    editor.putInt("dayOfMonth", dp1.getDayOfMonth());
    editor.putInt("hour", tp1.getCurrentHour());
    editor.putInt("minute", tp1.getCurrentMinute());
    editor.commit();
}

private void LoadPreferences() {
    SharedPreferences sharedPreferences = this.getSharedPreferences("preferences", MODE_PRIVATE);
    c = Calendar.getInstance();

    try {
        dp1.init(sharedPreferences.getInt("year", c.YEAR), sharedPreferences.getInt("month", c.MONTH),
                sharedPreferences.getInt("dayOfMonth", c.DAY_OF_MONTH), null);
    } catch (IllegalArgumentException e) {
        // TODO Auto-generated catch block
        dp1.init(2012, 5, 1, null);
    }
    tp1.setCurrentHour(sharedPreferences.getInt("hour", c.HOUR_OF_DAY));
    tp1.setCurrentMinute(sharedPreferences.getInt("minute", c.MINUTE));
}

}

The app runs fine, with all the expected entries in the Log cat file:

06-01 18:21:04.049: I/ApplicationPackageManager(7750): cscCountry is not German : XEU
06-01 18:21:04.079: I/TAG(7750): Resuming
06-01 18:21:04.089: I/MyActvity(7750): Year = 2014
06-01 18:21:04.089: W/TAG(7750): Resumed
06-01 18:21:05.459: W/KeyCharacterMap(7750): No keyboard for id 0
06-01 18:21:05.459: W/KeyCharacterMap(7750): Using default keymap:    /system/usr/keychars/qwerty.kcm.bin
06-01 18:21:05.519: I/ApplicationPackageManager(7750): cscCountry is not German : XEU
06-01 18:21:05.619: W/Picker(7750): beforeTextChanged: 01, 0, 2, 2
06-01 18:21:05.619: W/Picker(7750): onTextChanged: 01
06-01 18:21:05.619: W/Picker(7750): onTextChanged: 01, 0, 2, 2
06-01 18:21:05.619: W/Picker(7750): aftertextchanged: 01
06-01 18:21:05.619: W/Picker(7750): beforeTextChanged: 01, 0, 2, 2
06-01 18:21:05.619: W/Picker(7750): onTextChanged: 01
06-01 18:21:05.619: W/Picker(7750): onTextChanged: 10, 0, 2, 2
06-01 18:21:05.619: W/Picker(7750): aftertextchanged: 10
06-01 18:21:05.619: W/Picker(7750): beforeTextChanged: 2012, 0, 4, 4
06-01 18:21:05.619: W/Picker(7750): onTextChanged: 2012
06-01 18:21:05.619: W/Picker(7750): onTextChanged: 2014, 0, 4, 4
06-01 18:21:05.619: W/Picker(7750): aftertextchanged: 2014
06-01 18:21:08.239: E/DatePicker(7750): adjustMaxDat : 31 10
06-01 18:21:08.239: W/Picker(7750): beforeTextChanged: 10, 0, 2, 2
06-01 18:21:08.249: W/Picker(7750): onTextChanged: 10
06-01 18:21:08.249: W/Picker(7750): onTextChanged: 01, 0, 2, 2
06-01 18:21:08.249: W/Picker(7750): aftertextchanged: 01
06-01 18:21:08.259: W/Picker(7750): beforeTextChanged: 01, 0, 2, 2
06-01 18:21:08.259: W/Picker(7750): onTextChanged: 01
06-01 18:21:08.259: W/Picker(7750): onTextChanged: 10, 0, 2, 2
06-01 18:21:08.259: W/Picker(7750): aftertextchanged: 10
06-01 18:21:08.259: W/Picker(7750): beforeTextChanged: Jun, 0, 3, 3
06-01 18:21:08.259: W/Picker(7750): onTextChanged: Jun
06-01 18:21:08.259: W/Picker(7750): onTextChanged: Jul, 0, 3, 3
06-01 18:21:08.269: W/Picker(7750): aftertextchanged: Jul
06-01 18:21:10.759: I/TAG(7750): Resuming
06-01 18:21:10.759: I/MyActvity(7750): Year = 2014
06-01 18:21:10.759: W/TAG(7750): Resumed

However it does not update the TextView's timeUntil(). I could believe I had done something wrong here but for two issues. Firstly timeUntil() IS updated when onResume() runs on start-up (after onCreate()), and secondly timeUntil(), IS updated if you change the orientation of the screen. I understand that re-orientation of the screen reruns onCreate() which would suggest that onResume() is working after an onCreate() but not when running on its own. I am completely at a loss.

Does anyone have any ideas?

Following input from Proxy32 (see below) I have changed the onResume void to

@Override
protected void onResume() {
    super.onResume();

    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            h.post(new Runnable() {
                @Override
                public void run() {
                    Log.i("TAG", "Resuming");
                    SharedPreferences sharedPreferences = getSharedPreferences("preferences", MODE_PRIVATE);
                    Log.i("MyActvity", "Year = " + sharedPreferences.getInt("year", Calendar.YEAR));

                    leaving.set(sharedPreferences.getInt("year", Calendar.YEAR), sharedPreferences.getInt("month", Calendar.MONTH),
                            sharedPreferences.getInt("dayOfMonth", Calendar.DAY_OF_MONTH),
                            sharedPreferences.getInt("hour", Calendar.HOUR_OF_DAY), sharedPreferences.getInt("minute", Calendar.MINUTE));
                    Log.d("TAG", "date " + sdf.format(leaving.getTime()));
                    timeUntil.setText("Time until: " + sdf.format(leaving.getTime()));
                    timeUntil.invalidate();
                    today = Calendar.getInstance();
                    long millisToGo = leaving.getTimeInMillis() - today.getTimeInMillis();
                    long seconds2go = TimeUnit.MILLISECONDS.toSeconds(millisToGo);
                    tvSeconds.setText(String.format("%,d seconds", seconds2go));
                    long minutes2go = TimeUnit.MILLISECONDS.toMinutes(millisToGo);
                    tvMinutes.setText(String.format("%,d minutes", minutes2go));
                    long hours2go = TimeUnit.MILLISECONDS.toHours(millisToGo);
                    tvHours.setText(String.format("%,d hours", hours2go));
                    tvDays.setText(String.format("%,d days %d hours", (int) hours2go / 24, hours2go % 24));
                    long days2go = TimeUnit.MILLISECONDS.toDays(millisToGo);
                    tvWeeks.setText(String.format("%,d weeks %d days", (int) days2go / 7, days2go % 7));
                }
            });
        }
    }, 0, 1000);
    Log.w("TAG", "Resumed");

}

I have removed afficher too. This now does what I want it to do. Problem solved.

steve.watson128
  • 51
  • 1
  • 1
  • 7
  • My continuing research leads me to believe that the code is correct and that it should work. However, I am reassured by the fact that other people seem to have a similar problem, even if the strategies suggested are not working in my case: e.g. invalidate(). – steve.watson128 Jun 02 '12 at 04:02

2 Answers2

1

I'm not sure if I understand the question, but I'll will try to clarify what I can.

onResume is called after onStart (and/or onRestart) after onCreate. That is why it behaves as you have suggested after you change screen configuration, or when the app first starts.

See this for details: http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

This also means that timeUntil should be updated when you return to the original main activity. However, I do not see in your code where you are finishing your supplementary activity. Additionally, what do you mean by "run on its own?"

Jaypoulz
  • 110
  • 11
  • Thanks, yes I have seen the Activity Lifecyle chart before. My question I was really why it is that timeUntil does not update when the Activity editDate is destroyed and control returns to Days2goActivity, especially as (as can be seen by the Log Cat) onResume() runs. I mean that when onResume() runs following the destruction of the editDate Activity (i.e. without running onCreate(), hence "on it's own") timeUntil does not update, when onResume runs FOLLOWING onCreate (at start-up or when the orientation is changed), timeUntil IS updated. – steve.watson128 Jun 01 '12 at 20:12
0

try TextView invalidate() method after you set the text

Proxy32
  • 711
  • 5
  • 18
  • Changed the onResume() to timeUntil.setText("Time until: " + sdf.format(leaving.getTime())); timeUntil.invalidate(); Unfortunately, no effect. – steve.watson128 Jun 01 '12 at 20:23
  • try one test for me Log.d(TAG, "date " + sdf.format(leaving.getTime())); – Proxy32 Jun 02 '12 at 03:28
  • Happy to. Where do you want me to put the tag, in onResume, after the new line invalidate()? – steve.watson128 Jun 02 '12 at 03:42
  • Done that @Proxy32. Here is the (not surprising but still puzzling) result, the last 4 lines of logcat (all previous lines were similar to above and took place before the destruction of editDate. 06-02 05:43:37.039: I/TAG(1391): Resuming 06-02 05:43:37.039: I/MyActvity(1391): Year = 2015 06-02 05:43:37.039: D/TAG(1391): date Thu 09-Jul-2015 10:00 06-02 05:43:37.059: W/TAG(1391): Resumed – steve.watson128 Jun 02 '12 at 03:45
  • Ok so I have taken another look at your code. You have r which is a runnable nut running on the UI thread and that initiates the afficher method which does some UI updates. Thing is You cannot update the UI from another thread. so try handler.post(new Runnable(){ @Override public void run() { //Add any UI updates here ie. tvDays.setText("so on"); } }); – Proxy32 Jun 04 '12 at 17:51
  • Thanks, I have put the new code in the `onResume` void. I have removed (well commented out) the `Runnable r` declaration. However, it is still not working and I have lost my timed updates (because the h.postDelayed` has also been removed. I know I am being thick, but I have always struggled with the concept of threads, is there a reference you can direct me to to gain a better understanding. – steve.watson128 Jun 06 '12 at 07:40
  • Timer Task can be used for Timed Execution http://developer.android.com/reference/java/util/TimerTask.html AsyncTask can be used for performing tasks on another thread http://developer.android.com/reference/android/os/AsyncTask.html – Proxy32 Jun 06 '12 at 20:35