I am new to this part of android, and here I aim to use alarm manager to run a code snippet every 2 minute which will poll a server (using the website's api) and based on the returned JSON generate notification.
After a looking up the web I thought one of the best option in my case will be using intent service and android.
Manifest of Services and Recievers
<service
android:name=".NotifyService"
android:enabled="true"
android:exported="false" >
</service>
<receiver
android:name=".TheReceiver"
android:enabled="true"
android:exported="true" >
</receiver>
<receiver
android:name=".OnOffReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
Part in the flash screen activity where I call the intent service which is responsible for polling for notification:
Intent msgIntent = new Intent(this, NotifyService.class);
startService(msgIntent);
The receiver to start the alarm on device start:
public class OnOffReceiver extends BroadcastReceiver
{
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
public OnOffReceiver(){}
#Override
public void onReceive(Context context, Intent intent)
{
Intent service = new Intent(context, NotifyService.class);
service.setAction(NotifyService.CREATE);
context.startService(service);
}
}
The IntentService Class
public class NotifyService extends IntentService
{
public NotifyService()
{
super("NotifyService");
}
public static final int STATUS_RUNNING = 0;
public static final int STATUS_FINISHED = 1;
public static final int STATUS_ERROR = 2;
#Override
protected void onHandleIntent(Intent intent)
{
if (intent != null)
{
final String action = intent.getAction();
}
StartStuff();
}
public void StartStuff()
{
Intent intent = new Intent(this, TheReceiver.class);
PendingIntent pend_intent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,1200,1200, pend_intent);
//1200ms to make it easier to test
}
}
The receiver class which sets notification, for testing pupose I am not doing any network related work here just making a simple notification to check if the app is running in all situations
public class TheReceiver extends BroadcastReceiver
{
public TheReceiver(){}
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, " Success ", Toast.LENGTH_SHORT).show();
Log.d("Notification", "The Receiver Successful");
showNotification(context);
}
private void showNotification(Context context)
{
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context).setContentTitle("My notification").setContentText("Hello World!");
mBuilder.setDefaults(Notification.DEFAULT_SOUND);
mBuilder.setAutoCancel(true);
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, mBuilder.build());
}
}
However the notification come only when the app is running or in the recent apps tray.
It does not start notifying when the phone reboots, nor does it notify after the app is removes from the recent apps tray.
The app needs Notify users like other apps (like gmail, whatsapp) do, even if they are swiped out of the recent apps tray.
Timeliness and punctuality are not very big issue as delay up to 5 to 10 minutes are tolerable. (I intend to poll ever 2 minutes though.)
Where am I going wrong? Also, is there a better way to go about the problem?
To keep a receiver active after closing the app is to use
android:process=":remote"
in the manifest file for the receiver that needs to be kept alive.
<receiver
android:name=".TheAlarmReceiver"
android:process=":remote">
</receiver>
in the manifest for the receiver (TheReceiver in this case) that we need to keep active after the app closes.
P.S. : I also changed the way I use IntentsService and AlarmManager for the application, as my previous(above) implementation is not a very good way to go around it.
If an App is killed from recent apps or from "force stop" it won't restart by itself. The user has to start the app again in order to make it run again. There is no way to prevent this. It's just the way android works.
However there is a way to make your app run oon boot. Check out this link.
Related
So, I've been trying to achieve that for at least five hours today and I've tried literally ANY solution found anywhere.
I'm programming a little clock app, using AlarmManager to make the app ring. It works fine when my app is open or minimized. I'm trying to make it work when the app is closed, and that's the problem. So, there is the piece of code that sets the AlarmManager :
AlarmManager am = (AlarmManager) ctxt.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(ctxt, AlarmService.class);
PendingIntent pen = PendingIntent.getBroadcast(ctxt, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
am.setExact(AlarmManager.RTC_WAKEUP, nextRing.getTime(), pen);
(Here, ctxt is the context, I've tried both getApplicationContext() and getBaseContext() and nextRing.getTime() is a long that represents the date)
Then, I have my AlarmService class (wich used to be a service, which explain the name, but is now a BroadcastReceiver and I just don't want to rename it now)
public class AlarmService extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
/*Intent cust = new Intent(context, CustomIntent.class);
context.startService(cust);*/
Bundle extras = intent.getExtras();
Intent newIntent = new Intent(context, AlarmActivity.class);
newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
newIntent.putExtra("AlarmName", extras.getString("AlarmName"));
context.startActivity(newIntent);
}
}
So this is the try with only the BroadcastReceiver, wich doesn't work obviously, so I tried to add a IntentService (commented out code at the top) which has the following code
public class CustomIntent extends IntentService {
public CustomIntent() {
super("CustomIntent");
}
#Override
protected void onHandleIntent(Intent intent) {
Intent newIntent = new Intent(getBaseContext(), AlarmActivity.class);
newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplication().startActivity(newIntent);
}
}
... and that's not working either ! Finally, here's the manifest I use :
<application>
[Here goes stuff that have nothing to do with my bug]
<receiver android:name=".custom_classes.AlarmService"/>
<service
android:name="com.group9.abclock.custom_classes.CustomIntent"
android:enabled="true" >
<intent-filter>
<action android:name="com.group9.abclock.custom_classes.CustomIntent" />
</intent-filter>
</service>
</application>
Sorry for the (very) long post but I tough I should explain anything I tried. Thanks in advance if you can help !
If your application is closed, you can't trigger a BroadcastReceiver because it's not registered, and you can't use Context methods because there is no Context.
If you want to execute tasks while the application is closed, you have to create another project with a Service, and start it with your application.
A Service runs in background until someone kill it, and once it's started, the main application is not needed anymore. So the ring functionality have to be implemented in this service.
Just remember that the AlarmManager.setExact, is not that exact from API 23, due to Doze Mode.
My alarm is killed when OS kills the app. I thought that was one of the points of an Alarm, that it would keep running even though OS killed the app? I check the life of the Alarm using the "./adb shell dumpsys alarm" command, and every time OS kills my app, the Alarm is also gone. How I start my Alarm:
public static void startLocationAlarm(Context context){
if(ActivityLifecycleHandler.isApplicationInForeground()) {
return; // If App is in foreground do not start alarm!
}
String alarm = Context.ALARM_SERVICE;
AlarmManager am = ( AlarmManager ) context.getSystemService( alarm );
Intent intent = new Intent(locationBroadcastAction);
PendingIntent pi = PendingIntent.getBroadcast( context.getApplicationContext(), 0, intent, 0 );
int type = AlarmManager.ELAPSED_REALTIME_WAKEUP;
long interval = ONE_MINUTE;
long triggerTime = SystemClock.elapsedRealtime() + interval;
am.setRepeating(type, triggerTime, ONE_MINUTE, pi );
}
To add some more context, I am trying do some location operation in a service (not IntentService) in background. Here is my receiver. Used Wakeful because I did not want the service to be killed before it was done.
public class LocationBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent ) {
Intent myIntent = new Intent( context, LocationServiceAlarmOwnGoogleClient.class );
//context.startW( myIntent );
LocationBroadcastReceiver.startWakefulService(context, myIntent);
}
}
For some more information: I cancel the alarm in OnStart method of several activities that the user can return to after having it in the background. I do not know if that can cause this weird behaviour? Here is my cancel method:
public static void stopLocationAlarm(Context context){
Intent intent = new Intent(locationBroadcastAction);
PendingIntent sender = PendingIntent.getBroadcast(context.getApplicationContext(), 0, intent, 0);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(context.ALARM_SERVICE);
alarmManager.cancel(sender);
}
You can add service which listens to the phone's turning on callback.
add this permission into the manifest
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
and register reciever
<receiver android:name=".util.notification.local.MyBootCompletedService">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
public class MyBootCompletedService extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
AlarmReceiver.startLocalNotificationService(context);
}
}
The error that caused the Alarm to be canceled had actually nothing to do with the code, but had to do with special battery settings on Huawei devices. If your app is not set as "protected" in "protected apps", the system will cancel your alarm when it kills the app. Adding your app to "protected apps" will solve this problem. Same goes for Xiaomi devices. Have to add them to "Protected apps", then the Alarm will work as intended. Thank you #CommonsWare for leading me to the solution.
I've found a lot of solutions here about the Alarm Manager but none of them seemed to work.
I create the background service with:
public void scheduleSync() {
Intent intent = new Intent(this, SyncReceiver.class);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), SYNC_INTERVAL, pendingIntent);
Log.d(TAG, "Sync scheduled.");
}
The SyncReceiver class is:
public class SyncReceiver extends BroadcastReceiver {
private static final String TAG = "SyncReceiver";
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, WebBackendSyncService_.class);
context.startService(i);
Log.d(TAG, "WebBackendSyncService started.");
}
}
And that is the WebBackendSyncService defined with Android Annotations:
#EIntentService
public class WebBackendSyncService extends IntentService {
public static final String ACTION = "com.invoicing.networking.WebBackendSyncService";
private static final String TAG = "WebBackendSyncService";
#RestService
APIService restClient;
public WebBackendSyncService() { super(ACTION);}
#Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "Handling sync intent.");
sendInvoices();
}
#Background
void sendInvoices() {
SyncData.sendInvoices(restClient);
}
}
Service and Broadcast receiver in the manifest:
<service
android:name=".networking.WebBackendSyncService_"
android:exported="false" />
<receiver
android:name=".networking.SyncReceiver"
android:process=":remote" />
Looking at those line for the past couple of hours pushed me to ask for help here. I hope you'll see something that I'm missing.
Looking at the console output it gets to "Sync scheduled."
First, your <service> element has a rogue underscore in the android:name attribute that you need to remove.
Second, get rid of android:process=":remote". Forking a whole process for a two-line BroadcastReceiver is not very efficient, and it will interfere with the next fix.
Third, switch from BroadcastReceiver to WakefulBroadcastReceiver and follow the instructions for using that class, as right now the device will readily fall asleep either before or during the service's work.
Resolved after removing unused dependencies and multi-dex config. Zero changes to the code itself, however, it works for some unknown reason.
I'm trying to use a background service so that I can check for new content on the app every 30 minutes and notify the user with a notification if there is any new content. The problem is that that service does not seem that it is starting at all. I'm not entirely sure what I have wrong.
I've followed this article to implement a notification service and this question as well - Trying to start a service on boot on Android.
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.____.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.____.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name="com.____.NotificationService"/>
</application>
The BootReceiver should start the Service
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent startServiceIntent = new Intent(context, NotificationService.class);
context.startService(startServiceIntent);
}
}
The service NotificationService right now is set to display a simple notification
public class NotificationService extends Service {
private WakeLock mWakeLock;
/**
* Simply return null, since our Service will not be communicating with
* any other components. It just does its work silently.
*/
#Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* This is where we initialize. We call this when onStart/onStartCommand is
* called by the system. We won't do anything with the intent here, and you
* probably won't, either.
*/
private void handleIntent(Intent intent) {
// obtain the wake lock
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My App");
mWakeLock.acquire();
// check the global background data setting
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
if (cm.getActiveNetworkInfo() == null) {
stopSelf();
return;
}
// do the actual work, in a separate thread
new PollTask().execute();
}
private class PollTask extends AsyncTask<Void, Void, Void> {
/**
* This is where YOU do YOUR work. There's nothing for me to write here
* you have to fill this in. Make your HTTP request(s) or whatever it is
* you have to do to get your updates in here, because this is run in a
* separate thread
*/
#SuppressLint("NewApi") #Override
protected Void doInBackground(Void... params) {
// do stuff!
// get last added date time of offer
// every 60 minutes check for new offers
Notification notification = new Notification.Builder(getApplicationContext())
.setContentText("New Content Available")
.setSmallIcon(R.drawable.ic_launcher)
.setWhen(0)
.build();
return null;
}
/**
* In here you should interpret whatever you fetched in doInBackground
* and push any notifications you need to the status bar, using the
* NotificationManager. I will not cover this here, go check the docs on
* NotificationManager.
*
* What you HAVE to do is call stopSelf() after you've pushed your
* notification(s). This will:
* 1) Kill the service so it doesn't waste precious resources
* 2) Call onDestroy() which will release the wake lock, so the device
* can go to sleep again and save precious battery.
*/
#Override
protected void onPostExecute(Void result) {
// handle your data
stopSelf();
}
}
/**
* This is deprecated, but you have to implement it if you're planning on
* supporting devices with an API level lower than 5 (Android 2.0).
*/
#Override
public void onStart(Intent intent, int startId) {
handleIntent(intent);
}
/**
* This is called on 2.0+ (API level 5 or higher). Returning
* START_NOT_STICKY tells the system to not restart the service if it is
* killed because of poor resource (memory/cpu) conditions.
*/
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
handleIntent(intent);
return START_NOT_STICKY;
}
/**
* In onDestroy() we release our wake lock. This ensures that whenever the
* Service stops (killed for resources, stopSelf() called, etc.), the wake
* lock will be released.
*/
public void onDestroy() {
super.onDestroy();
mWakeLock.release();
}
}
Debugging the app with breakpoints in both BootRecevier and NotificationService are never triggered. Maybe I'm misunderstanding the way Background Services work.
UPDATE
I found this article about why the BroadcastRecevier is not being called. One of the mentioned points is PendingIntent requestCode missing
I've updated the BootRecevier as follows to test out the service...called every 1 minute:
#Override
public void onReceive(Context context, Intent intent) {
int minutes = 1;
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, NotificationService.class);
PendingIntent pi = PendingIntent.getService(context, 54321, i, 0);
am.cancel(pi);
if (minutes > 0) {
am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + minutes*60*1000,
minutes*60*1000, pi);
}
}
Changing 0 to a 'unique' requestCode 54321 somehow started triggering the service. The issue is that the service does not carry on working when the app is closed...not sure if that's a completely different thing altogether.
UPDATE 2
I've updated the doInBackground method in the NotificationService, using this example to display notifications:
#SuppressLint("NewApi") #Override
protected Void doInBackground(Void... params) {
Context mContext = getApplicationContext();
// invoke default notification service
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mContext);
mBuilder.setContentTitle("[Notification Title]");
mBuilder.setContentText("[Notification Text]");
mBuilder.setTicker(mContext.getString(R.string.app_name));
mBuilder.setSmallIcon(R.drawable.ic_launcher);
Intent resultIntent = new Intent(mContext, MainActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(mContext);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_ONE_SHOT);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, mBuilder.build());
return null;
}
I've tested it on an emulator and the Background Service works even when the app is closed. However, testing the app on an actual device did not display any notifications.
You need to declare the permission to receive the intent in your manifest.
AndroidManifest.xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
http://developer.android.com/reference/android/Manifest.permission.html#RECEIVE_BOOT_COMPLETED
You will only receive notifications of the device booting after the user has started your application at least once.
I happened to have the same issue recently, and I am using a 5.1.1 android smartphone. The way I solved this issue was using the ic_launcher in mipmap to replace the ic_launcher in drawable when called setSmallIcon().
However, for the exact reason, I guess it has something to do with the difference between mipmap and drawable.
Ref: mipmap vs drawable folders
I am starting a service (or re-starting the running service) when an activity is launched, using :
Intent intent = new Intent(this, MyService.class);
startService(intent);
Later on based on certain actions, the same activity binds to the service using
bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE);
And when the activity is destroyed, I call
unbindService(mConnection);
Earlier, the service used to restart when I killed the same activity/application from the application tray and showed the "message 1 process 1 service running" under running apps.
Now, the service does not restart on killing the same activity/application.
And I get the message "0 process 1 service running", which means the service is actually not running.
The service does not restart on application being closed. My application consists of one activity. Also the service is successfully started when launched after a system boot.
Why does the process of the service gets killed when I start it using startService() ??
edit
The service used to re-start earlier after i closed the app from the application tray. But now suddenly with the SAME code, it doesn't. It happens with other apps too when i close them. eg.
Here is a workaround I came across and works well for re-starting a service if its process is killed on closing the application. In your service, add the following code.
I came across this workaround in this thread.
#Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);
super.onTaskRemoved(rootIntent);
}
Seems to be a bug that the process of the application is killed. There is no point for a service to run if its process is killed.
Please be aware of that: onDestroy is not always called. You should not put code that way.
When activity forced closed or closed by system abnormally, onDestroy is not getting called.
Unfortunately, this is a complicated problem due to the way Android works. There are a number of strategies that each work around different parts of the problem. For best results, combine multiple strategies together.
Note that some of these strategies may no longer be necessary in more recent Android versions.
1. Start an activity
What to do
Taken from Foreground service killed when receiving broadcast after acitivty swiped away in task list:
In the foreground service:
#Override
public void onTaskRemoved( Intent rootIntent ) {
Intent intent = new Intent( this, DummyActivity.class );
intent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
startActivity( intent );
}
In the manifest:
<activity
android:name=".DummyActivity"
android:theme="#android:style/Theme.NoDisplay"
android:enabled="true"
android:allowTaskReparenting="true"
android:noHistory="true"
android:excludeFromRecents="true"
android:alwaysRetainTaskState="false"
android:stateNotNeeded="true"
android:clearTaskOnLaunch="true"
android:finishOnTaskLaunch="true"
/>
(If your service is in a different process then set this activity's process to the same one.)
In DummyActivity.java:
public class DummyActivity extends Activity {
#Override
public void onCreate( Bundle icicle ) {
super.onCreate( icicle );
finish();
}
}
Side effects
Causes the recents activity to close. Normally, swiping away an app doesn't close the recents activity.
Disadvantages
This only takes effect when the dummy activity starts, which may take half a second or more, so this still leaves the service open to being killed for a bit.
Explanation
When you remove/swipe your app away, a flag called waitingToKill is set. While this flag is set, Android may kill the process at any point in the future, such as when you receive a broadcast. Starting an activity clears this flag.
2. Spam a BroadcastReceiver with foreground broadcasts
What to do
Merge this into your service code:
if (Build.VERSION.SDK_INT >= 16) {
Intent intent = new Intent(this, DummyReceiver.class);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
//This seems to be timing-related; the more times we do this,
//the less likely the process gets killed
for (int i = 0; i < 50; ++i)
sendBroadcast(intent);
}
Create a dummy broadcast receiver:
public class DummyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {}
}
Add the receiver to your manifest:
<receiver android:name=".DummyReceiver" />
Side effects
May cause a slight (~250ms) delay/hang when the task is removed from the recents screen.
Disadvantages
This only keeps the process alive while it is receiving the broadcasts. the waitingToKill flag is still set, so the process may still be killed afterwards, such as when a broadcast is received.
Explanation
If your process isn't running in foreground priority, Android will try to kill it immediately. Receiving foreground broadcasts temporarily prevents this, resulting in the waitingToKill flag being set instead.
3. Don't bind to services
Binding to a service seems to increase the likelihood of the service's process being killed immediately when a task is removed.
I know this question is old but I recently encountered this problem and suddenly my service get stopped on closing app. Earlier it was working fine. This problem wasted my lot of time. To others who have similar problem make sure that YOUR BACKGROUND DATA RESTRICTION IS OFF.
This was the problem I had and it actually makes sense as when background data is Restricted background process won't run.
onDestroy is not always called. The Main problem in your case is ur unable to start the service when app closed,that time android OS(In Some OS) will kill the service, If you are not able to restart the service then call a alarm manger to start the reciver like this,
Manifest is,
<service
android:name=".BackgroundService"
android:description="#string/app_name"
android:enabled="true"
android:label="Notification" />
<receiver android:name="AlarmReceiver">
<intent-filter>
<action android:name="REFRESH_THIS" />
</intent-filter>
</receiver>
IN Main Activty start alarm manger in this way,
String alarm = Context.ALARM_SERVICE;
AlarmManager am = (AlarmManager) getSystemService(alarm);
Intent intent = new Intent("REFRESH_THIS");
PendingIntent pi = PendingIntent.getBroadcast(this, 123456789, intent, 0);
int type = AlarmManager.RTC_WAKEUP;
long interval = 1000 * 50;
am.setInexactRepeating(type, System.currentTimeMillis(), interval, pi);
this will call reciver and reciver is,
public class AlarmReceiver extends BroadcastReceiver {
Context context;
#Override
public void onReceive(Context context, Intent intent) {
this.context = context;
System.out.println("Alarma Reciver Called");
if (isMyServiceRunning(this.context, BackgroundService.class)) {
System.out.println("alredy running no need to start again");
} else {
Intent background = new Intent(context, BackgroundService.class);
context.startService(background);
}
}
public static boolean isMyServiceRunning(Context context, Class<?> serviceClass) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
if (services != null) {
for (int i = 0; i < services.size(); i++) {
if ((serviceClass.getName()).equals(services.get(i).service.getClassName()) && services.get(i).pid != 0) {
return true;
}
}
}
return false;
}
}
And this Alaram reciver calls once when android app is opened and when app is closed.SO the service is like this,
public class BackgroundService extends Service {
private String LOG_TAG = null;
#Override
public void onCreate() {
super.onCreate();
LOG_TAG = "app_name";
Log.i(LOG_TAG, "service created");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(LOG_TAG, "In onStartCommand");
//ur actual code
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// Wont be called as service is not bound
Log.i(LOG_TAG, "In onBind");
return null;
}
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.i(LOG_TAG, "In onTaskRemoved");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i(LOG_TAG, "In onDestroyed");
}
}
when there is no binding to a service or well established foreground then android system recognize the service as unused overloading service that should be shut down. Here is the best way to maintain your service even if the app is closed: AlarmManager or Service