Reputation: 479
The purpose of the service is to keep track of time since a button was pressed. If the menuactivity is showing, it updates some values on the menuactivity every minute using a timer, otherwise, it just updates itself.
It seems to work fine when the application is open or closed, but when the phone is off it slows down to less than half of what it should be (only showing like 10 minutes have passed after 21 real minutes have passed).
int startTime; //time at which the button is pressed
int time; //the current time, relative to startTime
@Override
public int onStartCommand(Intent intent, int flags, int startId){
startTime = (int)(System.nanoTime()/1000000000.0);
UpdateTimeTask updateTimeTask = new UpdateTimeTask();
timer = new Timer();
timer.schedule(updateTimeTask, 0, UPDATE_PERIOD); //update period is 60,000 (60 seconds)
return START_STICKY;
}
public class UpdateTimeTask extends TimerTask {
public void run() {
updateMenu();
}
}
public void updateMenu(){
time = (int) Math.round((System.nanoTime() / 1000000000.0) - startTime);
if(serviceCallbacks != null){ //it wont be null if its on menuactivity
serviceCallbacks.updateTimeElapsed(time/3600, time/60 - (time/3600) * 60);
}
}
If I have my phone off for a while and then go back in to menuactivity, it doesn't "fix itself" after a few cycles. I thought onStartCommand might be called more than once, but the only time the service can possibly be started is when the button is pressed.
Upvotes: 0
Views: 53
Reputation: 479
The accepted answer is correct, but only solved part of the problem. The other problem was that I was using System.nanoTime() instead of .currentTimeMillis(); .nanoTime() stops when the screen is off. Putting this here for possible future googlers.
Upvotes: 2
Reputation: 38289
but the only time the service can possibly be started is when the button is pressed
That is not true. When your app go into the background (is no longer visible) it becomes a candidate to be killed if the system needs memory for other higher ranked apps. Also, the user can kill your app by swiping it from the task list. Because the service returns START_STICKY
from onStartCommand()
, the system will restart the service after some period of time, calling onStartCommand()
with a null intent. This behavior makes a service unsuitable as the home for a data item you want to retain, such as startTime
.
An alternative is to persist the value in SharedPreferences. A service is not needed and the periodic update processing can be done in your activity using the postDelayed() method of any view.
This sample activity outlines the basic logic:
public class ButtonActivity extends Activity {
private static final String TIME_KEY = "time";
private static final long PERIOD = 60*1000; // 60 seconds
private SharedPreferences mPrefs;
private Button mButton;
private TextView mTimeView;
private Runnable mDisplayTask = new Runnable() {
@Override
public void run() {
// show the time elapsed since button press in milliseconds
long elapsed = System.currentTimeMillis() - mPrefs.getLong(TIME_KEY, 0);
mTimeView.setText(""+elapsed);
// schedule next display update
mTimeView.postDelayed(mDisplayTask, PERIOD);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPrefs = getPreferences(MODE_PRIVATE);
// clear the button press time
setPressTime(0);
setContentView(R.layout.activity_demo);
mButton = (Button)findViewById(R.id.button);
mTimeView = (TextView)findViewById(R.id.time);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// save the button press time
setPressTime(System.currentTimeMillis());
// start the display updates
mDisplayTask.run();
}
});
}
@Override
protected void onPause() {
super.onPause();
// activity no longer visible; stop the updates
mTimeView.removeCallbacks(mDisplayTask);
}
@Override
protected void onResume() {
super.onResume();
// activity is visible
// if the button has been pressed, start the display updates
if (mPrefs.getLong(TIME_KEY, 0) > 0) {
mDisplayTask.run();
}
}
private void setPressTime(long time) {
// persist the button press time
SharedPreferences.Editor ed = mPrefs.edit();
ed.putLong(TIME_KEY, time);
ed.commit();
}
}
Upvotes: 2