I've a sticky background service which has to run all the time. Basically it keeps track of the time, its a custom clock timer. But once the device goes to idle state (when phone screen is turned off) the timer (background service) also gets paused.
What should I do to make it always keep running even when the screen is turned off?
public class TimerService extends Service {
private Context context;
#Override
public IBinder onBind(Intent intent) {
Logger.LogI(TAG, "Service binding");
return null;
}
#Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
}
So there were some ways for a service not to be killed when device goes in sleep mode.
I started my service as a foreground service attached with the notification. I don't say that its the better approach for a long term service. But of-course this solution is open for more optimization. This solution doesn't get the service go in pause state while in sleep mode.
Following is the whole service code:
public class TimerService extends Service {
private ScheduledExecutorService scheduleTaskExecutor;
private Context context;
#Override
public IBinder onBind(Intent intent) {
Logger.LogI(TAG, "Service binding");
return null;
}
#Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
setNotification();
if (scheduleTaskExecutor == null) {
scheduleTaskExecutor = Executors.newScheduledThreadPool(1);
scheduleTaskExecutor.scheduleAtFixedRate(new mainTask(), 0, 1, TimeUnit.SECONDS);
}
return Service.START_STICKY;
}
public void setNotification() {
PendingIntent contentIntent;
contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, Main_Activity.class), 0);
NotificationManager mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.notification_icon)
.setColor(this.getResources().getColor(R.color.action_bar_color))
.setContentTitle("MainActivity")
.setOngoing(true)
.setAutoCancel(false)
.setContentText("MyApp");
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
Notification notification = mBuilder.build();
startForeground(NOTIFICATION_ID, notification); //NOTIFICATION_ID is a random integer value which has to be unique in an app
}
}
private class mainTask implements Runnable {
public void run() {
// 1 Second Timer
}
}
Helpful Links:
Run a service in the background forever..? Android
How to run background service after every 5 sec not working in android 5.1?
How to run a method every X seconds
How to make service run even in sleep mode?
part-1 persistent foreGround android service that starts by UI, works at sleep mode too, also starts at phone restart
part-2 persistent foreGround android service that starts by UI, works at sleep mode too, also starts at phone restart
Android - implementing startForeground for a service?
If you want make your service as never ending service then User this code in onStartCommand
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Put code here
return START_REDELIVER_INTENT;
}
You can use START_STICKY also.
Related
In my app I use a foreground service that must run constantly. Sometimes the foreground service is stopped.
Under what circumstances can the OS kill my service (it happen even if there is enough memory, battery is full, phone is charging)?
This is what my code looks like until now:
public class ServiceTest extends Service {
public static Thread serverThread = null;
public Context context = this;
public ServiceTest(Context context) {
super();
this.context = context;
}
public ServiceTest() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
if (this.serverThread == null) {
this.serverThread = new Thread(new ThreadTest());
this.serverThread.start();
}
return START_STICKY;
}
private class ThreadTest implements Runnable {
#Override
public void run() {
Intent notificationIntent = new Intent(context, MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Notification notification = new NotificationCompat.Builder(context)
.setContentTitle("Notification title")
.setContentText("Notification text")
.setContentIntent(pendingIntent)
.setAutoCancel(false)
.setSmallIcon(R.drawable.android)
.setOngoing(true).build();
startForeground(101, notification);
while(true){
//work to do
}
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
There is not a single... Many problems in your code... You may be getting it "0 Errors" as it is syntactically correct but it is androidicaly wrong, your basics are poor, reading of android documentation and implementation is very poor. Android never runs very poor things...
Problem : 1
Do you know for a service conventionally you should override onCreate, onStartCommand, onBind, onDestroy methods....?
I don't see onDestroy there....!!
Problem : 2
Do you know how to notify...? Your onStartCommand implementation is again making no sense.
KEEP IT EMPTY JUST RETURN START_STICKY
Problem : 3
How do you expect to run this under background execution limits...? Notify android first by making notification in oncreate only and with startforeground if needed...
I don't see it there.... you trying to do it in onstartcommand and again it is very poorly...
Well... take a look at working code below :
public class RunnerService extends Service
{
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "1";
public RunnerService() { }
#Override
public void onCreate()
{
super.onCreate();
Log.d("RUNNER : ", "OnCreate... \n");
Bitmap IconLg = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground);
mNotifyManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this, null);
mBuilder.setContentTitle("My App")
.setContentText("Always running...")
.setTicker("Always running...")
.setSmallIcon(R.drawable.ic_menu_slideshow)
.setLargeIcon(IconLg)
.setPriority(Notification.PRIORITY_HIGH)
.setVibrate(new long[] {1000})
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setOngoing(true)
.setAutoCancel(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);
// Configure the notification channel.
notificationChannel.setDescription("Channel description");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.setVibrationPattern(new long[]{1000});
notificationChannel.enableVibration(true);
notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
mNotifyManager.createNotificationChannel(notificationChannel);
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
startForeground(1, mBuilder.build());
}
else
{
mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
mNotifyManager.notify(1, mBuilder.build());
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d("RUNNER : ", "\nPERFORMING....");
return START_STICKY;
}
#Override
public void onDestroy()
{
Log.d("RUNNER : ", "\nDestroyed....");
Log.d("RUNNER : ", "\nWill be created again automaticcaly....");
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent)
{
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("NOT_YET_IMPLEMENTED");
}
}
How to check....???
Remove the app from recents list and you should see in your logs the "Performing " message in logcat...
In what conditions it stops...?
It never stops ( until next boot..!! )... Yes it stops when user force stops application. And rarely if system finds it is having very low resources .... which is a very rare condition seems to occur as android has improved a lot over the time....
How to start it....?????
Wherever it may be from mainactivity or from receiver or from any class :
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
context.startForegroundService(new Intent(context, RunnerService.class));
}
else
{
context.startService(new Intent(context, RunnerService.class));
}
How to check is service started or not....?
Simply Don't..... Even if you starts service how many times you wants.... If it is already running... then it won't be start again.... If not running then... will start it...!!
The criticism made in the chosen answer is not reasonable if the service needs an intent to work.
On higher version of Android, System will pause any foreground service while the device is locked, to minimize the power consumption even if it returns START_STICKY. So, to make a foreground task constantly, a wakelock is required.
Here's what android documentation describes wakeLock:
To avoid draining the battery, an Android device that is left idle quickly falls asleep. However, there are times when an application needs to wake up the screen or the CPU and keep it awake to complete some work.
To make a foreground service running constantly, acquire a wakeLock from inside the onCreate().
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyApp::MyWakelockTag");
wakeLock.acquire();
For further detail, have a look at official Android Documentation.
I am new to android. I have already developed android application which starts service when application starts.
What I have :
Currently when application starts, it creates sticky notification in notification area as shown in screenshot.
Source code for service :
public class InfiniteService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
Intent notificationIntent = new Intent();
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(getString(R.string.app_name))
.setContentText("Welcome To TestApp")
.setContentIntent(pendingIntent).build();
startForeground(1337, notification);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Log.e("InfiniteService", "Service started");
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
//Log.e("InfiniteService", "onDestroy");
sendBroadcast(new Intent("InfiniteService"));
}
What I want :
I want to get rid of this sticky notification in notification area. Instead I want service that runs in background continuously.
What I have tried :
I tried 'return START_NON_STICKY' in onStartCommand with initial impression that it will remove sticky notification but later learned from here that START_STICKY tells the OS to recreate the service after it has enough memory
I was suspecting PendingIntent is making this but again after reading explanation, come to know that it is not what I am looking for.
Then I searched how to create sticky notification in android hoping to get some clue. After reading this article, got to know flags makes it sticky. I searched "Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT" in my entire code but did not find anything.
What am I missing? Any pointers/help would be great. Thanks.
What i want: To run a background service that would communicate with our server via RESTFUL webservice after regular interval of 1 minute (Its a strict project requirement. So cannot increase it.)
What i have: I tried various approaches using simple BroadcastReceivers with a simple Service AND WakefulBroadcastReceivers using WakefulIntentService etc..
Main Problem: The main issue is when device screen is ON, everything is working fine on regular/fixed intervals but when the screen goes off OR devices gets locked, then the alarm Manager triggers service with a minimum interval of 5 Minutes.. Thats exactly what i dont want. I want the same 1 minute interval while device is locked/screen off.
Below is my code:
Manifest.xml
<uses-permission android:name="android.permission.WAKE_LOCK" />
<receiver android:name=".MyScheduledReceiver" />
<service android:name=".BackgroundService" />
Activity.java
MyScheduledReceiver.scheduleAlarms(MainActivity.this);
gradle
// Background long running process
compile 'com.commonsware.cwac:wakeful:1.0.+'
repositories {
maven {
url "https://s3.amazonaws.com/repo.commonsware.com"
}
}
BroadcastReceiver
public class MyScheduledReceiver extends WakefulBroadcastReceiver {
private static final int PERIOD = 60 * 1000;
private static final int INITIAL_DELAY = 2000; // 5 seconds
#Override
public void onReceive(Context context, Intent i) {
try {
if (i.getAction() == null) {
WakefulIntentService.sendWakefulWork(context, BackgroundService.class);
} else {
scheduleAlarms(context);
}
} catch (Exception e) {
e.printStackTrace();
}
}
static void scheduleAlarms(Context ctxt) {
AlarmManager mgr = (AlarmManager) ctxt.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(ctxt, MyScheduledReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(ctxt, 0, i, 0);
mgr.setRepeating(AlarmManager.RTC_WAKEUP, INITIAL_DELAY, PERIOD, pi);
}
}
BackgroundService
public class BackgroundService extends WakefulIntentService {
public BackgroundService() {
super("BackgroundService");
}
#Override
protected void doWakefulWork(Intent intent) {
sendNotification("HELLOO");
stopSelf();
}
#Override
public void onTaskRemoved(Intent rootIntent) {
MyScheduledReceiver.scheduleAlarms(BackgroundService.this);
super.onTaskRemoved(rootIntent);
}
private void sendNotification(String message) {
try {
Intent intent = intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Notification notification;
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("test")
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
notification = notificationBuilder.build();
notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Currently i am simply showing a notification with a sound in the notification bar from my BackgroundService.
I would really appreciate your help. Thanks !
What you want is not supported on Android 6.0 anyway. Android 6.0 will not issue alarms every minute, to any application, thanks to Doze mode.
The closest thing that will work is:
Have a service that uses a ScheduledExecutorService to get control every minute to do your work
Have that service acquire a WakeLock and keep the CPU on all the time
Have that service use startForeground() and START_STICKY to minimize the amount of time that it is not around and therefore incapable of doing this work
Make sure that application is added to the "ignore battery optimizations" whitelist in Settings
Ignore the cries of anguish from users, complaining that their battery life is atrocious
Try using like this
public static void scheduleAlarms(Context ctxt) {
AlarmManager mgr = (AlarmManager)ctxt.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(ctxt, MyScheduledReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(ctxt,REQUEST_CODE, i, 0);
// We want the alarm to go off 3 seconds from now.
long firstTime = SystemClock.elapsedRealtime();
firstTime += 3 * 1000;//start 3 seconds after first register.
mgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime,
600000, sender);//10min interval
}
Have you tried using a Handler to obtain this goal? AlarmManager will typically work on a battery friendly rhythm when possible. Whereas Handlers are much more exact.
For example, you could run this code in your Service:
// Store this as a member variable
private Handler mHandler = new Handler();
// This can be a member variable or local
private Runnable runnable = new Runnable() {
#Override
public void run() {
// Do stuff
// Tell the Handler to call itself again
mHandler.postDelayed(this, 60000);
}
};
// Put this at the start of `Service`
mHandler.postDelayed(runnable, 60000);
As Commonsware points out, having the Handler declared as it is above would cause the Handler to run on the Main Thread. Here is some documentation on how to get a Handler to run in the background:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
I'm trying to cancel an upload service from my progress notification using the 'cancel' button.
But I cannot get this working.
Notification is created
//Intent class changes from first activity then to service when it's uploading.
Intent cancel = new Intent(intentClass, BaseUploadService.class);
PendingIntent cancelUploadIntent = PendingIntent.getBroadcast(intentClass, 0, cancel, PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder
.setSmallIcon(R.drawable.notificationicon)
.setContentTitle(title)
.setContentText(filename)
.setAutoCancel(totalAmount > uploadedAmount)
.setProgress((int) totalAmount, (int) uploadedAmount, false)
.addAction(R.string.assignment_icon_group, intentClass.getString(R.string.cancel), cancelUploadIntent)
;
return builder.build();
Listen for intent from notification button.
public class BaseUploadService extends IntentService {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.debug("onStartCommand - BaseUploadService");
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
public BaseUploadService(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent intent) {
}
}
Nothing is ever received in the service.
+ there could be multiple services.
Change PendingIntent.getBroadcast() to PendingIntent.getService().
If after that change the service is still not started, try building the notification with setContentIntent instead of addAction.
Check your manifest to confirm that BaseUploadService is declared correctly.
This is onStartCommand()
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Notification creation code
telMgr = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
telMgr.listen(new PSL(), PhoneStateListener.LISTEN_CALL_STATE);
return super.onStartCommand(intent, flags, startId);
}
and PhoneStateListener class (under service class)
public class PSL extends PhoneStateListener {
public void onCallStateChanged(int state, String incomingNum) {
switch(state) {
case TelephonyManager.CALL_STATE_IDLE:
case TelephonyManager.CALL_STATE_OFFHOOK:
//Work1
break;
case TelephonyManager.CALL_STATE_RINGING:
//Work2
break;
}
}
}
both of them are in same .java file
I have these code on one service class.
when I call startService() from main activity, it works well.
but when my app is killed by Task Manager, Killer or automatically by shortage of memory on device, Service does restarts but not working.
when i go to Setting - Application - Running, it shows process 1 and service 1, before/after killed.but after killed, memory share goes 1/10. I have tried startForeground() not to be killed easily with my notification - it didn't work. (doesn't show any notification)
and also tried return of onStartCommand(): START_STICKY, START_REDELIVER_INTENT - shows same result is there any way I can restart completely or make it not killed?
After Spending few Hours I fount that , For Android 2.0 or later you can use the startForeground() method to start your Service in the foreground.
Documentation provided by Android
A started service can use the startForeground(int, Notification) API to put the service in a foreground state, where the system considers it to be something the user is actively aware of and thus not a candidate for killing when low on memory. (It is still theoretically possible for the service to be killed under extreme memory pressure from the current foreground application, but in practice this should not be a concern.)
Ther are very rare chances of Foreground Service to kill by OS.But It works fine.
public class ServicePhoneState extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("Music Player")
.setTicker("Google Music Player")
.setContentText("My Music")
.setSmallIcon(R.drawable.ic_bg_icon)
.setPriority(Notification.PRIORITY_MAX)
.setContentIntent(pendingIntent)
.setOngoing(false)
.build();
startForeground(10, notification);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
stopForeground(true);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
I solved it by startForeground()
It didn't work because I had not used Notification.FLAG_FOREGROUND_SERVICE on Notification
After Spending few Hours I fount that , For Android 2.0 or later you can use the startForeground() method to start your Service in the foreground.
Documentation provided by Android
A started service can use the startForeground(int, Notification) API to put the service in a foreground state, where the system considers it to be something the user is actively aware of and thus not a candidate for killing when low on memory. (It is still theoretically possible for the service to be killed under extreme memory pressure from the current foreground application, but in practice this should not be a concern.) Ther are very rare chances of Foreground Service to kill by OS.But It works fine.
public class ServicePhoneState extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
MyPhoneStateListener phoneListener = new
MyPhoneStateListener(ServicePhoneState.this);
TelephonyManager telephony = (TelephonyManager)
getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("Music Player")
.setTicker("Google Music Player")
.setContentText("My Music")
.setSmallIcon(R.drawable.ic_bg_icon)
.setPriority(Notification.PRIORITY_MAX)
.setContentIntent(pendingIntent)
.setOngoing(false)
.build();
startForeground(10, notification);
return START_NOT_STICKY;}
#Override
public void onDestroy() {
super.onDestroy();
stopForeground(true);
}
#Override
public IBinder onBind(Intent intent) {
return null;}}