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...
Related
Hello I created Broadcast Receiver in the Service class to receive application notifications but it doesn't receive any intents from Notification. When I make the broadcast receiver static, the problem is solved but at this time I cannot access the elements of the non-static upper class. I have to solve this without making it static.
My Code:
public class BackgroundService extends Service {
private final int TASK_DELAY = 0;
private final int TASK_PERIOD = 5 * 1000;
int NOTIFICATION_ID = 1;
private Context context;
private NotificationCompat.Builder builder;
private NotificationManager notificationManager;
private static Timer timer;
private PendingIntent test;
private int runRate;
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//User pressed a notifiacition button
Log.w(TAG, "onReceive: Recived" );
}
// constructor
public MyReceiver(){
}
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
public static Timer getTimer() {
return timer;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onCreate() {
Toast.makeText(this, "Service has been started!", Toast.LENGTH_SHORT).show();
context = getApplicationContext();
timer = new Timer();
runRate = 0;
builder = new NotificationCompat.Builder(context)
.setSmallIcon(android.R.drawable.ic_dialog_alert)
.setContentTitle("KolBoost")
.setContentText("Arkaplan servisi etkinleştirildi!")
.setAutoCancel(false)
.setPriority(NotificationCompat.PRIORITY_HIGH);
MyReceiver myReceiver = new MyReceiver();
IntentFilter filter = new IntentFilter();
Intent close = new Intent(getBaseContext(), BackgroundService.class);
close.setAction("CLOSE_SERVICE");
PendingIntent closeServiceIntent = PendingIntent.getBroadcast(getBaseContext(), 0, close, 0);
Intent i2 = new Intent(getBaseContext(), BackgroundService.class);
i2.setAction("BOOST_MEMORY");
PendingIntent boostIntent = PendingIntent.getBroadcast(getBaseContext(), 0, i2, 0);
Intent launch = new Intent(getBaseContext(),BackgroundService.class);
launch.setAction("OPEN_MANAGER");
PendingIntent contentIntent = PendingIntent.getBroadcast(getBaseContext(), 0, launch, 0);
builder.setContentIntent(contentIntent);
builder.addAction(0, "Clear Memory", boostIntent);
builder.addAction(0, "Exit", closeServiceIntent);
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(getBaseContext(), MainActivity.class);
test = PendingIntent.getActivity(getBaseContext(), NOTIFICATION_ID, notificationIntent, PendingIntent.FLAG_NO_CREATE);
//I'm adding actions to intentFilter.
filter.addAction(close.getAction());
filter.addAction(i2.getAction());
filter.addAction(launch.getAction());
//Registering Receiver with intentFilter
registerReceiver(myReceiver,filter);
super.onCreate();
}
#Override
public void onDestroy() {
timer.cancel();
notificationManager.cancelAll();
Log.d(TAG, "onDestroy: Destroyed");
super.onDestroy();
}
}
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
I want to send push notifications in my app but after few minutes android kill my background service and notifications not showing. How to make background service which android will not close?
BackroundService.class
public Context context = this;
public android.os.Handler handler = new Handler();
public static Runnable runnable = null;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Log.e("Service", "Service crated!");
runnable = new Runnable() {
public void run() {
Log.e("Service", "Service is still running!");
Toast.makeText(context, "Service is still running", Toast.LENGTH_SHORT).show();
handler.postDelayed(runnable, 50000);
}
};
handler.postDelayed(runnable, 15000);
}
#Override
public void onDestroy() {
}
#Override
public void onStart(Intent intent, int startid) {
Log.e("Service", "Service started by user!");
}
AlarmReceiver.class
#Override
public void onReceive(Context context, Intent intent) {
int notificationId = intent.getIntExtra("ID", 0);
String message = intent.getStringExtra("TEXT");
String tittle = intent.getStringExtra("TITTLE");
Intent mainIntent = new Intent(context, BackgroundService.class);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, mainIntent, 0);
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification.Builder builder = new Notification.Builder(context);
builder.setSmallIcon(R.drawable.finance43)
.setContentTitle(tittle)
.setContentText(message)
.setWhen(System.currentTimeMillis())
.setAutoCancel(true)
.setContentIntent(contentIntent)
.setPriority(Notification.PRIORITY_HIGH)
.setCategory(Notification.CATEGORY_MESSAGE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String channelId = "REMINDERS";
NotificationChannel channel = new NotificationChannel(channelId,
"Reminder",
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
builder.setChannelId(channelId);
}
notificationManager.notify(notificationId, builder.build());
}
When I start app i see "Service is still running!" for about 1 hour.
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]
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);