Timer in the Service - java

I have an app that records the time of the job, i mean that calculates the job time for that purpose i used chronometer to run the time. Since the job is 9 hours long so user can't open the app for that long. For that purpose i am using the Service which indicate the time. Since i cannot use Chronometer because
Chronometer is a UI widget (actually a TextView) in Android. So, i can't use it for non-UI purposes. So i have to use timer to do the job. But i do not know how can i achieve this. Any code or help is appreciated. Thanks
When i hit the start button the chronometer starts like this
and my service also started but i get the time as 00:00:00 like this
i just want that timer should run in the service and i can see the time in service and i do not want to deal or use the time that is running in service, the time in service will show user that how much time they spend on job.
Service Class
public class ServiceTimer extends Service {
// Chronometer chronometer ;
//String valueOfTime ;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String input = intent.getStringExtra("inputExtra");
// chronometer = new Chronometer(this);
//chronometer.setText("00:00:00");
//chronometer.setOnChronometerTickListener(new //Chronometer.OnChronometerTickListener() {
// #Override
// public void onChronometerTick(Chronometer chronometer) {
// CharSequence text = chronometer.getText();
// if (text.length() == 5) {
// chronometer.setText("00:"+text);
// } else if (text.length() == 7) {
// chronometer.setText("0"+text);
// }
//}
// });
// chronometer.start();
//before i know about chronometer that i cannot use it in service
// this is what i have so for with chronometer to achieve
// but failed ...
Intent notificationIntent = new Intent(this, Timer_FullTime.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(chronometer.getText().toString())
.setSmallIcon(R.mipmap.logoback)
.setContentText(input)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
//do heavy work on a background thread
//stopSelf();
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
UPDATE this is how i get what i wanted or asked in the question
public class ServiceTimer extends Service {
private int THE_ID_TO_UPDATE = 1;
private static Timer timer = new Timer();
private Context ctx;
private int second = 0 ;
NotificationManager notificationManager ;
private int minute = 0 ;
private int hour = 0 ;
//we are going to use a handler to be able to run in our TimerTask
final Handler handler = new Handler();
NotificationCompat.Builder notification ;
#Override
public void onCreate() {
super.onCreate();
super.onCreate();
ctx = this;
}
private class mainTask extends TimerTask
{
public void run()
{
second = second + 1 ;
if (second == 60){
minute++ ;
second = 0 ;
}
if (minute == 60){
hour++;
minute = 0 ;
second = 0 ;
}
notification.setContentText( hour + "h " + minute + "m " + second+"s");
notificationManager.notify(THE_ID_TO_UPDATE , notification.build());
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String input = intent.getStringExtra("inputExtra");
Intent notificationIntent = new Intent(this, Timer_FullTime.class) ;
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0) ;
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notification = new NotificationCompat.Builder(this, CHANNEL_ID);
notification.setContentTitle(input);
notification.setSmallIcon(R.mipmap.logoback);
notification.setOnlyAlertOnce(true);
notification.setWhen(System.currentTimeMillis());
notification.setContentIntent(pendingIntent);
notification.setLights(Color.RED, 1000, 1000);
notification.setVibrate(new long[]{0, 400, 250, 400});
notification.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
notification.build();
notificationManager.notify(THE_ID_TO_UPDATE , notification.build());
startForeground(THE_ID_TO_UPDATE, notification.build());
timer.scheduleAtFixedRate(new mainTask(), 0, 1000);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}

You could try to use a Timer with a TimerTask:
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// Update your counter/notification each second
}
}, 0, 1000);
Link to official documentation: https://developer.android.com/reference/java/util/Timer

Related

How can I restart the timer, after it was cancelled?

I've got this service, which starts a timer, whenever said service also starts. The idea is that, if the user manually turns on the screen (i.e. the app. enters in the "counter" BroadcastReceiver), the timer gets cancelled. Otherwise, if the timer finishes by itself, the service will automatically stop (via onDestroy, of course).
My problem comes when I want to restart the service, WITHOUT killing the app. first. If I simply input a new number of seconds and start the service, I get the following error: java.lang.IllegalStateException: Timer was canceled
How can I get rid of said problem?
MainService:
public class MainService extends Service {
static String BROADCAST_ACTION = "com.example.vladpintea.friendsbeforecents.displayevent";
Handler handler = new Handler();
Intent intentForStars;
String usedTimer;
long interval;
TimerTask myTask = new TimerTask() { public void run() { stopSelf(); } };
Timer myTimer = new Timer();
#Override
public void onCreate() {
Toast.makeText(MainService.this, "Service, Created", Toast.LENGTH_SHORT).show();
intentForStars = new Intent(BROADCAST_ACTION);
registerReceiver(counter, new IntentFilter(Intent.ACTION_SCREEN_ON));
}
private BroadcastReceiver counter = new BroadcastReceiver() {
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onReceive(Context context, Intent intent) {
myTimer.cancel();
NotificationManager notify_manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Intent intent_main_activity = new Intent(context, MainActivity.class);
PendingIntent pending_intent_main_activity = PendingIntent.getActivity(context, 0,
intent_main_activity, 0);
Notification notification_popup = new Notification.Builder(context)
.setContentTitle("Friends Before Cents")
.setContentText("Oh, no! You've Lost. Try Again?")
.setSmallIcon(R.mipmap.ic_sentiment_very_dissatisfied_white_48dp)
.setContentIntent(pending_intent_main_activity)
.setAutoCancel(true)
.build();
notify_manager.notify(0, notification_popup);
Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, 30000);
}
};
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(MainService.this, "Service, Started", Toast.LENGTH_SHORT).show();
try { usedTimer = intent.getStringExtra("timer"); } catch (NullPointerException ignored) {}
try { interval = Long.parseLong(usedTimer); } catch (NumberFormatException ignored) {}
myTimer.schedule(myTask, interval * 1000);
handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, 1000);
return super.onStartCommand(intent, flags, startId);
}
private Runnable sendUpdatesToUI = new Runnable() {
public void run() { handler.postDelayed(this, 1000); }
};
public void addStars() { sendBroadcast(intentForStars); }
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onDestroy() {
unregisterReceiver(counter);
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
| PowerManager.ACQUIRE_CAUSES_WAKEUP
| PowerManager.ON_AFTER_RELEASE, "MyWakeLock");
wakeLock.acquire();
Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, 30000);
NotificationManager notify_manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Intent intent_main_activity = new Intent(this.getApplicationContext(), MainActivity.class);
PendingIntent pending_intent_main_activity = PendingIntent.getActivity(this, 0,
intent_main_activity, 0);
Notification notification_popup = new Notification.Builder(this)
.setContentTitle("Friends Before Cents")
.setContentText("Congrats! You've Won Some Coins.")
.setSmallIcon(R.mipmap.ic_sentiment_very_satisfied_white_48dp)
.setContentIntent(pending_intent_main_activity)
.setAutoCancel(true)
.build();
notify_manager.notify(0, notification_popup);
addStars();
}
#Override
public IBinder onBind(Intent intent) { return null; }
You can not, the Doc reference states that once cancelled you need to create a new instance...
the Doc:
Note that calling this method from within the run method of a
repeating timer task absolutely guarantees that the timer task will
not run again.
So basically after cancel you need a new one...

Android service timer crash

I'm developing an app. In it user can input his friend's information - name and date of birth. When information is added, a service should start which should count how much time left and send a notification, when friend is having a birthday soon. Service takes info from database. When I add information, service just crashes. Here's my service code
Timer timer = new Timer();
DB2 db;
Cursor cursor;
Calendar x = Calendar.getInstance();
int y = x.get(Calendar.YEAR);
int m = x.get(Calendar.MONTH) + 1;
int d = x.get(Calendar.DAY_OF_MONTH);
int h = x.get(Calendar.HOUR_OF_DAY);
int min = x.get(Calendar.MINUTE);
int s = x.get(Calendar.SECOND);
Handler handler;
NotificationManager nm;
int l, p, a, i, month, hours, minutes, seconds, m22, d22, v, g, t;
int[] k = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
class UpdateTimeTask extends TimerTask{
public void run(){
MS2.this.runOnUiThread(new Runnable() {
#Override
public void run() {
db.open();
cursor = db.getAllData();
cursor.moveToFirst();
if (cursor.moveToFirst()) {
do {
int d110 = cursor.getInt(cursor.getColumnIndex("day")); //here it should do some manipulations with every item in DB.
}
while (cursor.moveToNext());//takes next item
}
}
});
cursor.close();
}
}
private void runOnUiThread(Runnable runnable) {
handler.post(runnable);
}
public void onCreate() {
super.onCreate();
handler = new Handler();
nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//db = new DB2(this);
//db.open();
}
public void not() {
Intent resultIntent = new Intent(this, TEST2.class);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("My notification")
.setContentText("Hello World!");
int mNotificationId = 001;
NotificationManager mNotifyMgr =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
this,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
mNotifyMgr.notify(mNotificationId, mBuilder.build());
}
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
db = new DB2(this);
db.open();
Toast.makeText(getApplicationContext(), "Service Running ", 1).show();
timer.schedule(new UpdateTimeTask(), 0, 1000);
return super.onStartCommand(intent, flags, startId);
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
When I have my code like this
class UpdateTimeTask extends TimerTask{
public void run(){
db.open();
cursor = db.getAllData();
cursor.moveToFirst();
if (cursor.moveToFirst()) {
do {
int d110 = cursor.getInt(cursor.getColumnIndex("day")); //here it should do some manipulations with every item in DB.
}
while (cursor.moveToNext());//takes next item
}
cursor.close();
}
}
There's no crash. Just no notification

Android Kitkat how to fix return_sticky bug in service

I found several posts regarding the return_sticky problem when using KitKat.
It seems like that the service can be killed and don't come back even when return_sticky.
I'm talking about a background service, not a foreground service.
I've tried several approaches but everything seems to fail. Heres a bit of code for demonstrating. After a while it gets killed and it won't come back:
public class RestPushService extends Service {
#Override
public void onDestroy() {
MainApplication.getDevice().writeBoolean("REST_PUSHSERVICE_RUNNING", false);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if ((intent != null) && (intent.getBooleanExtra("ALARM_RESTART_SERVICE_DIED", false))) {
if (MainApplication.getDevice().readBoolean("REST_PUSHSERVICE_RUNNING", false)){
ensureServiceStaysRunning();
return START_STICKY;
}
}
MainApplication.getDevice().writeBoolean("REST_PUSHSERVICE_RUNNING", true);
/** doing other stuff like creating a thread **/
return START_STICKY;
}
private void ensureServiceStaysRunning() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
final int restartAlarmInterval = 20 * 60 * 1000;
final int resetAlarmTimer = 2 * 60 * 1000;
final Intent restartIntent = new Intent(this, RestPushService.class);
restartIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
restartIntent.putExtra("ALARM_RESTART_SERVICE_DIED", true);
final AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Handler restartServiceHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 0, restartIntent, 0);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + restartAlarmInterval, pintent);
sendEmptyMessageDelayed(0, resetAlarmTimer);
}
};
restartServiceHandler.sendEmptyMessageDelayed(0, 0);
}
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Intent restartService = new Intent(getApplicationContext(), this.getClass());
restartService.setPackage(getPackageName());
PendingIntent restartServicePI = PendingIntent.getService(getApplicationContext(), 1, restartService, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 1000, restartServicePI);
}
}
Now another receiver which gets called when the device starts.
public class myReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null || action.equals("com.myapp.START_ALARM")) {
if (MainApplication.getDevice().hasInternet()) {
if (!MainApplication.getDevice().hasServiceRunning(RestPushService.class)) {
context.startService(new Intent(context, RestPushService.class));
} else {
Log.d(TAG, "RestPushService was aready running. Do nothing");
}
}
}
}
public void startRepeating(Context context) {
if (alarmManager == null) alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent("com.myapp.START_ALARM");
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * 60 * 30, pi); // Millisec * Second * Minute
}
public void stopRepeating(Context context) {
Intent intent = new Intent("com.myapp.START_ALARM");
PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
alarmManager.cancel(sender);
}
}
I've truncated much code because I think it is not relevant. I removed all try catches and null initializations to make sure it's easily readable. So what may be caused the "don't come back" crap?
I refer also to START_STICKY does not work on Android KitKat

Send notification every x seconds

I'm doing an app that checks the live scores. I don't know if it's the best way, but I created a Timertask, a Service and and Activity to notify.
The Timertask checks every x seconds if the score changes and if it changes, informs the Service.
If the Service is informed, it calls the Activity that will notify the user. My problem is I failed at calling the activity to Notify from the Service.
Here is my code (For the example, I didn't take the score but a variable i.
//import ...
public class MyService extends Service{
Notif notif = new Notif();
private static final String TAG = "MyService";
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Congrats! MyService Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
}
#Override
public void onStart(Intent intent, int startId) {
Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
Log.d(TAG, "onStart");
Timer time = new Timer(); // Instantiate Timer Object
final ScheduleTask st = new ScheduleTask(); // Instantiate SheduledTask class
time.schedule(st, 0, 5000); // Create Repetitively task for every 1 secs
}
#Override
public void onDestroy() {
Toast.makeText(this, "MyService Stopped", Toast.LENGTH_LONG).show();
Log.d(TAG, "onDestroy");
}
public void checkI(int i){
if (i==3){
notif.initializeUIElements();
}
}
}
TimerTask
import ...
// Create a class extends with TimerTask
public class ScheduleTask extends TimerTask {
MyService myService = new MyService();
Notif notif = new Notif();
int i = 0;
// Add your task here
public void run() {
i++;
System.out.println("affichage numero " + i );
myService.checkI(i);
}
public int getI() {
return i;
}
}
Notif
import ...
public class Notif extends Activity {
private static final int NOTIFY_ME_ID = 1987;
private NotificationManager mgr = null;
ScheduleTask scheduleTask = new ScheduleTask();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
}
void initializeUIElements() {
Notification note = new Notification(R.drawable.ic_launcher,
"Welcome to MyDoople.com", System.currentTimeMillis());
PendingIntent i = PendingIntent.getActivity(this, 0, new Intent(
this, MainActivity.class), Notification.FLAG_ONGOING_EVENT);
note.setLatestEventInfo(this, "MyDoople.com", "An Android Portal for Development",
i);
// note.number = ++count;
note.flags |= Notification.FLAG_ONGOING_EVENT;
mgr.notify(NOTIFY_ME_ID, note);
}
}
Services may be terminated by the system if resources are needed. For your requirement, it's best to use AlarmManager to periodically do something.
Here are more references: [1], [2]

AlarmManager won't start service

I just followed the exact code in API Demo, but my service just won't start after I set the AlarmManager.
so my service is
public class CourseWatcherRefreshService extends Service {
private CourseDbAdapter mDbHelper;
private CourseWatcher watcher;
#Override
public void onCreate() {
Toast.makeText(this, "Watcher Refresh Service starts", Toast.LENGTH_SHORT).show();
mDbHelper = new CourseDbAdapter(this);
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mDbHelper.open();
Thread thread = new Thread(null, mTast, "CourseWatcherRefreshService");
thread.start();
super.onCreate();
}
#Override
public void onDestroy() {
mDbHelper.close();
super.onDestroy();
}
Runnable mTast = new Runnable() {
// some work
};
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private final IBinder mBinder = new Binder() {
#Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
return super.onTransact(code, data, reply, flags);
}
};
}
Also in my AndroidManifest.xml, I put such code
<service
android:name=".CourseWatcherRefreshService"
android:process=":remote" >
</service>
And I use such code to toggle the AlarmManager
PendingIntent refreshIntent = PendingIntent.getActivity(NaviScreen.this, 0, new Intent(NaviScreen.this, CourseWatcherRefreshService.class), 0);
long firstTime = SystemClock.elapsedRealtime();
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,firstTime, 30*1000, refreshIntent);
And the code above is almost the same with the AlartService example in API Demo, but my code won't work, I can't see any sign of my service starts to work.
You are using getActivity when you should be using getService. So change the PendingIntent line to
PendingIntent refreshIntent = PendingIntent.getService(NaviScreen.this, 0, new Intent(NaviScreen.this, CourseWatcherRefreshService.class), 0);
try this :
Intent updateIntent = new Intent()
updateIntent.setClass(NaviScreen.this, CourseWatcherRefreshService.class)
PendingIntent pendingIntent = PendingIntent.getService(this, 0, updateIntent, 0);

Categories