Xamarin: Android Widget with timer, stops when app killed - android

I have this code:
public class MyWidgetProvider : AppWidgetProvider
{
public override void OnUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
Log.Debug("WIDGET", "Updating the widget");
// Open app on click
RemoteViews views = new RemoteViews(context.PackageName, Resource.Layout.MyWidget);
Intent launchAppIntent = new Intent(context, typeof(MainActivity));
PendingIntent launchAppPendingIntent = PendingIntent.GetActivity(context, 0, launchAppIntent, PendingIntentFlags.UpdateCurrent);
views.SetOnClickPendingIntent(Resource.Id.main, launchAppPendingIntent);
appWidgetManager.UpdateAppWidget(appWidgetIds[0], views);
// Start timer
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Elapsed += OnTimedEvent;
timer.Enabled = true;
}
private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
Log.Debug("WIDGET", "Updating status...");
new Handler(Looper.MainLooper).Post(() =>
{
//Run my code to periodically update the widget
});
}
}
And I would like to know why following occurs:
When I drop the widget on phone screen, the timer starts to run, this is ok.
When I click on the widget the app starts, timer continues to run, this is ok.
When I click on back button the app goes to background, timer continues to run, this is ok.
When I terminate the app in task manager the timer stops, this is bad.
When I click on the widget again the app starts but the timer does not resume operation, this is bad.
The timer resumes operation only when next OnUpdate is called (I have the lowest possible interval 30 minutes), this is bad because I need frequent updating when the screen is on (or better when the widget is visible to the user).
I would like know the basics here as I could not find any relevant information. Why the timer runs when I first drop the widget on screen (without running app) and stops when the app gets killed?
Yes I have read almost everything about widget basics, then about using AlarmManager, Service, JobService, JobIntentService, JobScheduler etc. But I am interested in this solution with timer as it is very simple and works across all present Android versions (even newest Oreo). Things to solve yet are to stop the timer when the screen goes off and start it again when it goes on. To save the phone battery.

This is how I solved it:
public static class WidgetConsts
{
public const string DebugTag = "com.myapp.WIDGET";
public const string ActionWakeup = "com.myapp.WIDGET_WAKEUP";
public const string ActionWidgetUpdate = "android.appwidget.action.APPWIDGET_UPDATE";
public const string ActionWidgetDisabled = "android.appwidget.action.APPWIDGET_DISABLED";
}
[BroadcastReceiver]
[IntentFilter(new string[] { WidgetConsts.ActionWakeup })]
public class AlarmReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action.Equals(WidgetConsts.ActionWakeup))
{
Log.Debug(WidgetConsts.DebugTag, "Wakeup alarm called");
if (MyWidgetProvider.widgetTimer == null)
{
Log.Debug(WidgetConsts.DebugTag, "Widget updating does not run, enforcing update...");
MyWidgetProvider.UpdateAppWidget(context);
}
else
{
Log.Debug(WidgetConsts.DebugTag, "Widget updating runs, no action needed");
}
}
}
}
[BroadcastReceiver]
[IntentFilter(new string[] { WidgetConsts.ActionWidgetUpdate })]
[IntentFilter(new string[] { WidgetConsts.ActionWidgetDisabled })]
[MetaData("android.appwidget.provider", Resource = "#xml/widget_info")]
public class MyWidgetProvider : AppWidgetProvider
{
public static System.Timers.Timer widgetTimer = null;
public override void OnUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
Log.Debug(WidgetConsts.DebugTag, "Updating the widget");
// Open app on click
RemoteViews views = new RemoteViews(context.PackageName, Resource.Layout.MyWidget);
Intent launchAppIntent = new Intent(context, typeof(MainActivity));
PendingIntent launchAppPendingIntent = PendingIntent.GetActivity(context, 0, launchAppIntent, PendingIntentFlags.UpdateCurrent);
views.SetOnClickPendingIntent(Resource.Id.main, launchAppPendingIntent);
appWidgetManager.UpdateAppWidget(appWidgetIds[0], views);
// set timer for updating the widget views each 5 sec
if (widgetTimer == null)
{
widgetTimer = new System.Timers.Timer();
widgetTimer.Interval = 5000;
widgetTimer.Elapsed += OnTimedEvent;
}
widgetTimer.Enabled = true;
// set alarm to wake up the app when killed, each 60 sec
// needs a fresh BroadcastReceiver because AppWidgetProvider.OnReceive is
// not virtual and overriden method in this class would not be called
AlarmManager am = (AlarmManager)context.GetSystemService(Context.AlarmService);
Intent ai = new Intent(context, typeof(AlarmReceiver));
ai.SetAction(WidgetConsts.ActionWakeup);
PendingIntent pi = PendingIntent.GetBroadcast(context, 0, ai, PendingIntentFlags.CancelCurrent);
am.SetRepeating(AlarmType.ElapsedRealtime, SystemClock.ElapsedRealtime(), 1000 * 60, pi);
}
public override void OnDisabled(Context context)
{
Log.Debug(WidgetConsts.DebugTag, "Disabling the widget");
if (widgetTimer != null)
{
Log.Debug(WidgetConsts.DebugTag, "Stopping timer");
widgetTimer.Enabled = false;
}
else
Log.Debug(WidgetConsts.DebugTag, "Timer is null");
base.OnDisabled(context);
}
private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
Log.Debug(WidgetConsts.DebugTag, "Updating status...");
new Handler(Looper.MainLooper).Post(() =>
{
//Run my code to periodically update the widget
RemoteViews views = new RemoteViews(Application.Context.PackageName, Resource.Layout.MyWidget);
AppWidgetManager manager = AppWidgetManager.GetInstance(Application.Context);
ComponentName thisWidget = new ComponentName(Application.Context, Java.Lang.Class.FromType(typeof(MyWidgetProvider)));
int[] appWidgetIds = manager.GetAppWidgetIds(thisWidget);
views.SetTextViewText(Resource.Id.myText, "my text");
manager.UpdateAppWidget(appWidgetIds[0], views);
});
}
static public void UpdateAppWidget(Context context)
{
Intent intent = new Intent(context, typeof(MyWidgetProvider));
intent.SetAction(WidgetConsts.ActionWidgetUpdate);
int[] ids = AppWidgetManager.GetInstance(context).GetAppWidgetIds(new ComponentName(context, Java.Lang.Class.FromType(typeof(MyWidgetProvider))));
intent.PutExtra(AppWidgetManager.ExtraAppwidgetIds, ids);
context.SendBroadcast(intent);
}
}
Pros:
Simple solution, works on all Android systems (tested on 3.2, 4.3, 8.1).
Battery friendly on Android systems >= 6.0 with doze mode (measured with GSam Battery monitor). Not restricted by the new background execution limits in >=8.0.
Cons:
Drains battery on systems below 6.0 without doze mode, but no one cares about these today...

First,You can try to make the Widget app not be skilled.
The widget itself will not be killed. The widget is originally a broadcastreciver, and it is static. This means that a subscribed broadcast widget can be received at any time, and the onReceive() method will be called. The reason why widgets can't be run is that they should be killed for the corresponding service. If want the widget to run all the time, the service should when be killed and be restarted.
Service is a component of the Android system, it is similar to the level of Activity, but he can not run by himself, can only run in the background, and can interact with other components.
In the Android development process, each time the startService (Intent) is called, the OnStartCommand(Intent, int, int) method of the Service object is called, and then some processing is done in the onStartCommand method.
1,Create the servide not be killed
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
return START_STICKY_COMPATIBILITY;
//return super.onStartCommand(intent, flags, startId);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
flags = START_STICKY;
return super.onStartCommand(intent, flags, startId);
// return START_REDELIVER_INTENT;
}
#Override
public void onStart(Intent intent, int startId)
{
// again regsiter broadcast
IntentFilter localIntentFilter = new IntentFilter("android.intent.action.USER_PRESENT");
localIntentFilter.setPriority(Integer.MAX_VALUE);// max int
myReceiver searchReceiver = new myReceiver();
registerReceiver(searchReceiver, localIntentFilter);
super.onStart(intent, startId);
}
2,Restart the Service in the Service's onDestroy().
public void onDestroy()
{
Intent localIntent = new Intent();
localIntent.setClass(this, MyService.class); // restart Service
this.startService(localIntent);
}
3,create a broadcast and regsiter in XML
public class myReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
context.startService(new Intent(context, Google.class));
}
}
<receiver android:name=".myReceiver" >
<intent-filter android:priority="2147483647" ><!--Priority plus highest-->
<!-- when applicayion lauch invoke -->
<action android:name="android.intent.action.BOOT_COMPLETED" />
<!-- unlock invole -->
<action android:name="android.intent.action.USER_PRESENT" />
<!--context switch -->
<action android:name="android.media.RINGER_MODE_CHANGED" />
</intent-filter>
</receiver>
<service android:name=".MyService" >
Note: Unlock, start, switch scene activation broadcast needs to add permissions, such as startup completion, and mobile phone status.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
==================================================================
Second, If Widget app not be skilled, you can listen to screen is lock or unlock.
Custom a ScreenListener and add ScreenBroadcastReceiver
private class ScreenBroadcastReceiver extends BroadcastReceiver {
private String action = null;
#Override
public void onReceive(Context context, Intent intent) {
action = intent.getAction();
if (Intent.ACTION_SCREEN_ON.equals(action)) { // screen on
mScreenStateListener.onScreenOn();
} else if (Intent.ACTION_SCREEN_OFF.equals(action)) { // screen off
mScreenStateListener.onScreenOff();
} else if (Intent.ACTION_USER_PRESENT.equals(action)) { // screen unlock
mScreenStateListener.onUserPresent();
}
}
}
so that you can do with Timers or other showing with customer.
==============================================================================
More info:
This method not the best, there are more places to improve,just give a suggestion.

Related

Stop Service from PendingIntent after Notifcation is opened

I want the service to perform a stopForeground and a stopSelf after the notification is clicked followed by the running of pendingIntent.
I have tried using a BroadcastReceiver which is never called as I checked during debugging. I have added it to manifest as well.
Intent intentHide = new Intent(this, StopServiceReceiver.class);
PendingIntent hide = PendingIntent.getBroadcast(this, (int) System.currentTimeMillis(), intentHide, PendingIntent.FLAG_CANCEL_CURRENT);
Added it to the builder
builder.setContentIntent(hide);
And the Broadcast Rec is done separately -
public class StopServiceReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 333;
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, TimerService.class);
context.stopService(service);
}
}
Manifest -
<receiver
android:name=".StopServiceReceiver"
android:enabled="true"
android:process=":remote" />
This is not working. The notification and the service both are alive.
Questions - Should I use addContent instead of setContentIntent ? If yes, then what should the parameters be ?
Is there anything I went wrong with? What could possibly be wrong with such kind of implementation? Thank you.
I had the same problem in the notification.
This code is working perfectly.
void creatnotifiaction()
{
public static final String STOP = "com.example.android";
public static final int REQUEST_CODE = 333;
filter = new IntentFilter();
filter.addAction(STOP);
Intent intentHide = new Intent(STOP);
PendingIntent hide = PendingIntent.getBroadcast(this,REQUEST_CODE,intentHide,PendingIntent.FLAG_CANCEL_CURRENT);
registerReceiver(broadcastReceiver, filter);
}
There no need to separate broadcast receiver use in same class.
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#SuppressLint("ResourceAsColor")
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.d("notification", "Received intent with action " + action);
switch (action) {
case STOP:
//your code to stop notifications or service.
break;
}
});
Let me know if that work for you.
Thanks...Happy coding.

Cannot keep android service alive after app is closed

I am trying to spawn a service that stays alive all the time, even if the user closes the application. According to these threads
Keep location service alive when the app is closed
Android Service Stops When App Is Closed
Android: keep Service running when app is killed
this can be accomplished with IntentServices or Service.START_STICKY
Yet, I tried both types of services without success. In other words, my services get killed when the app is closed by the user. Can someone point out if this is can be done and how? Here is what I have tried without success:
With IntentService:
public class MyIntentService extends IntentService {
private final int mPollingTimeMS = 500;
private int mInitializationPollingCount = 0;
private Thread mPollThread;
public MyIntentService() {
super("MyIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
mPollThread = new Thread() {
public void run() {
while (true) {
try {
Log.e(Constants.Engine.LOGGER_TAG_DEV,
"SDK Service Running: " +
mInitializationPollingCount * mPollingTimeMS +
"ms have elapsed");
mInitializationPollingCount++;
sleep(mPollingTimeMS);
} catch (Exception e) {
StackTraceElement trace = new Exception().getStackTrace()[0];
Logger.e(Constants.Engine.LOGGER_TAG_APP, "[Exception:" + e.toString() + "]" +
trace.getClassName() + "->" + trace.getMethodName() + ":" + trace.getLineNumber());
}
}
}
};
mPollThread.start();
}
}
and with Services:
public class MyService extends Service {
public MyService() {
}
private final int mPollingTimeMS = 500;
private int mInitializationPollingCount = 0;
private Thread mPollThread;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mPollThread = new Thread() {
public void run() {
while (true) {
try {
Log.e(Constants.Engine.LOGGER_TAG_DEV,
"SDK Service Running: " +
mInitializationPollingCount * mPollingTimeMS +
"ms have elapsed");
mInitializationPollingCount++;
sleep(mPollingTimeMS);
} catch (Exception e) {
StackTraceElement trace = new Exception().getStackTrace()[0];
Logger.e(Constants.Engine.LOGGER_TAG_APP, "[Exception:" + e.toString() + "]" +
trace.getClassName() + "->" + trace.getMethodName() + ":" + trace.getLineNumber());
}
}
}
};
mPollThread.start();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// I tried to return null here, but this
// service gets killed no matter what.
return null;
}
}
and here is the manifest:
<service
android:name=".mycompany.MyService"
android:enabled="true"
android:exported="true"
android:process=":process1">
</service>
<service
android:name=".mycompany.MyIntentService"
android:process=":process2"
android:exported="false">
</service>
I shall added that I am closing the test app not with a close button, but using the Android OS app manager. See picture below
Lastly, the driver activity (not much there)
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent1 = new Intent(getBaseContext(), MyService.class);
startService(intent1);
Intent intent2 = new Intent(getBaseContext(), MyIntentService.class);
startService(intent2);
}
}
I also try to add a notification and make it a foreground service but still the same thing. The moment I close the app, everything gets killed. This is what I added:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
showNotification();
...etc..
private void showNotification() {
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
int iconId = R.mipmap.ic_launcher;
int uniqueCode = new Random().nextInt(Integer.MAX_VALUE);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(iconId)
.setContentText("Context Text")
.setContentIntent(pendingIntent).build();
startForeground(uniqueCode, notification);
}
Here is an example of foreground service that I use and that works, it remains active when the app is closed. Of course, it also must be started, and for that task the app must be running at a first glance, or a receiver of a boot event must be set, but this is another story.
public class MyService extends Service {
static final int NOTIFICATION_ID = 543;
public static boolean isServiceRunning = false;
#Override
public void onCreate() {
super.onCreate();
startServiceWithNotification();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && intent.getAction().equals(C.ACTION_START_SERVICE)) {
startServiceWithNotification();
}
else stopMyService();
return START_STICKY;
}
// In case the service is deleted or crashes some how
#Override
public void onDestroy() {
isServiceRunning = false;
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
// Used only in case of bound services.
return null;
}
void startServiceWithNotification() {
if (isServiceRunning) return;
isServiceRunning = true;
Intent notificationIntent = new Intent(getApplicationContext(), MyActivity.class);
notificationIntent.setAction(C.ACTION_MAIN); // A string containing the action name
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent contentPendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.my_icon);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle(getResources().getString(R.string.app_name))
.setTicker(getResources().getString(R.string.app_name))
.setContentText(getResources().getString(R.string.my_string))
.setSmallIcon(R.drawable.my_icon)
.setLargeIcon(Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(contentPendingIntent)
.setOngoing(true)
// .setDeleteIntent(contentPendingIntent) // if needed
.build();
notification.flags = notification.flags | Notification.FLAG_NO_CLEAR; // NO_CLEAR makes the notification stay when the user performs a "delete all" command
startForeground(NOTIFICATION_ID, notification);
}
void stopMyService() {
stopForeground(true);
stopSelf();
isServiceRunning = false;
}
}
Then I run it with
Intent startIntent = new Intent(getApplicationContext(), MyService.class);
startIntent.setAction(C.ACTION_START_SERVICE);
startService(startIntent);
Please note the two constants used as Actions, these are Strings that must start with the package name.
IntentService
Using IntentService is probably not the best approach. By default IntentService stops itself after onHandleIntent(Intent) returns and there's no work left to do (i.e. the request queue is empty). This is explained in the official docs of IntentService:
When all requests have been handled, the IntentService stops itself, so you should not call stopSelf().
In your case, onHandleIntent(Intent) creates a thread but returns right away, which makes it stop by itself.
Service + startForeground()
Using a regular Service in foreground mode should work as long as you keep that service running on a separate process. For that, you need:
Make the onStartCommand() return START_STICKY.
Call the method to show the notification right in onCreate().
Run the service in a separate process (using android:process=":something").
Based on the post, it seems that you've tried some of these steps in isolation but never tried all of them at the same time.
If none of the answers above are working, maybe it is a manufacturer specific issue. Some MI phones, for instance, kill the foreground service when the user kill the app via task manager.
I recommend you to test the app on a virtual device, so you can check if it is or isn't this kind of issue.
Hope it helps!
You can simply call your service in your onStop() method inside your activity.
Even when user stops the app the service will still be running.
Try the answers for this similar question: Bad notification for startForeground in Android app

How to really update a widget precisely every minute

I'm stumped. I know this question has already been answered a hundred times but nothing I've tried works.
My question: I made an Android widget that needs to refresh precisely at each minute, much like all clock widgets do. (This widget tells me in how many minutes are left before my train leaves, a one minute error makes it useless).
Here are my attempts to far, and the respective outcomes:
I put android:updatePeriodMillis="60000" in my appwidget_info.xml. However, as specified in API Docs, "Updates requested with updatePeriodMillis will not be delivered more than once every 30 minutes" and indeed that's about how often my widget gets updated.
I tried using an AlarmManager. In my WidgetProvider.onEnabled:
AlarmManager am = (AlarmManager)context.getSystemService
(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
long now = System.currentTimeMillis();
// start at the next minute
calendar.setTimeInMillis(now + 60000 - (now % 60000));
am.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), 60000,
createUpdateIntent(context));
however as stated in the API docs, "as of API 19, all repeating alarms are inexact" and indeed my widget actually gets updated every five minutes or so.
Based on the previous point I tried setting targetSdkVersion to 18 and saw no difference (updates every five minutes or so).
The setRepeating documentation seems to recommend using setExact. I tried the following. At the end of my update logic:
Calendar calendar = Calendar.getInstance();
long now = System.currentTimeMillis();
long delta = 60000 - (now % 60000);
Log.d(LOG_TAG, "Scheduling another update in "+ (delta/1000) +" seconds");
calendar.setTimeInMillis(now + delta);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setExact(AlarmManager.RTC, calendar.getTimeInMillis(), //UPDATE_PERIOD_SECONDS * 1000,
createUpdateIntent(context));
It works perfectly for a couple minutes and then reverts to updating every five minutes or so (and not even near minute changes). Here are some timestamps of when the update intent is received:
21:44:17.962
21:52:37.232
21:59:13.872
22:00:00.012 ← hey suddenly it becomes exact again??
22:01:47.352
22:02:25.132
22:06:56.202
Some recommend using a Handler. I defined a Service which I start when the widget provider is enabled, and does this after update code:
int delay = (int)(60000 - (System.currentTimeMillis() % 60000));
Log.d(LOG_TAG, "Scheduling another update in " + delay/1000 + " seconds");
new Handler().postDelayed(new Runnable() {
public void run() {
Log.d(LOG_TAG, "Scheduled update running");
updateAppWidget();
}
}, delay);
and this one works perfectly for several hours, but then the service gets suddenly killed and gets "scheduled to restart after HUGE delay". Concretely, the widget just gets stuck at some point and doesn't get updated at all.
Some other options I've seen online: the linked post above suggests creating a foreground service (which, if I understand correctly, means having a permanently visible icon in my already crowded status bar. I don't have one permanent icon for each clock widget I use so that should not be necessary). Another suggestion is to run a high priority thread from the service, which feels awfully overkill.
I've also seen recommendations to use Timers and BroadcastReceivers but the former is said to be "not appropriate for the task" and I remember having trouble doing the latter. I think I had to do it in a service and then the service gets killed just like when I use Handlers.
It should be noted that the AlarmManager seems to work well when the phone is connected to the computer (presumably because it means the battery is charging), which doesn't help because most of the time I want to know when my train will leave is when I'm already on the way...
As the Handler is perfectly accurate but just stops working after a while, and the AlarmManager option is too inaccurate but does not stop working, I'm thinking of combining them by having AlarmManager start a service every ten minutes or so, and have that service use a Handler to update the display each minute. Somehow I feel this will get detected by Android as a power hog and get killed, and anyway I'm sure I must be missing something obvious. It shouldn't be that hard to do what's essentially a text-only clock widget.
EDIT: if it matters, I'm using my widget on a Samsung Galaxy Note 4 (2016-06-01) with Android 6.0.1.
Sorry, i totally forgot, was busy.. Well, i hope you got the idea of what you need, snippets are following, hope i dod not forgot something.
on the widget provider class.
public static final String ACTION_TICK = "CLOCK_TICK";
public static final String SETTINGS_CHANGED = "SETTINGS_CHANGED";
public static final String JOB_TICK = "JOB_CLOCK_TICK";
#Override
public void onReceive(Context context, Intent intent){
super.onReceive(context, intent);
preferences = PreferenceManager.getDefaultSharedPreferences(context);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName thisAppWidget = new ComponentName(context.getPackageName(), WidgetProvider.class.getName());
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget);
if (intent.getAction().equals(SETTINGS_CHANGED)) {
onUpdate(context, appWidgetManager, appWidgetIds);
if (appWidgetIds.length > 0) {
restartAll(context);
}
}
if (intent.getAction().equals(JOB_TICK) || intent.getAction().equals(ACTION_TICK) ||
intent.getAction().equals(AppWidgetManager.ACTION_APPWIDGET_UPDATE)
|| intent.getAction().equals(Intent.ACTION_DATE_CHANGED)
|| intent.getAction().equals(Intent.ACTION_TIME_CHANGED)
|| intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
restartAll(context);
onUpdate(context, appWidgetManager, appWidgetIds);
}
}
private void restartAll(Context context){
Intent serviceBG = new Intent(context.getApplicationContext(), WidgetBackgroundService.class);
context.getApplicationContext().startService(serviceBG);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
scheduleJob(context);
} else {
AppWidgetAlarm appWidgetAlarm = new AppWidgetAlarm(context.getApplicationContext());
appWidgetAlarm.startAlarm();
}
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void scheduleJob(Context context) {
ComponentName serviceComponent = new ComponentName(context.getPackageName(), RepeatingJob.class.getName());
JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
builder.setPersisted(true);
builder.setPeriodic(600000);
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
int jobResult = jobScheduler.schedule(builder.build());
if (jobResult == JobScheduler.RESULT_SUCCESS){
}
}
#Override
public void onEnabled(Context context){
restartAll(context);
}
#Override
public void onDisabled(Context context){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.cancelAll();
} else {
// stop alarm
AppWidgetAlarm appWidgetAlarm = new AppWidgetAlarm(context.getApplicationContext());
appWidgetAlarm.stopAlarm();
}
Intent serviceBG = new Intent(context.getApplicationContext(), WidgetBackgroundService.class);
serviceBG.putExtra("SHUTDOWN", true);
context.getApplicationContext().startService(serviceBG);
context.getApplicationContext().stopService(serviceBG);
}
WidgetBackgroundService
public class WidgetBackgroundService extends Service {
private static final String TAG = "WidgetBackground";
private static BroadcastReceiver mMinuteTickReceiver;
#Override
public IBinder onBind(Intent arg0){
return null;
}
#Override
public void onCreate(){
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null) {
if (intent.hasExtra("SHUTDOWN")) {
if (intent.getBooleanExtra("SHUTDOWN", false)) {
if(mMinuteTickReceiver!=null) {
unregisterReceiver(mMinuteTickReceiver);
mMinuteTickReceiver = null;
}
stopSelf();
return START_NOT_STICKY;
}
}
}
if(mMinuteTickReceiver==null) {
registerOnTickReceiver();
}
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
#Override
public void onDestroy(){
if(mMinuteTickReceiver!=null) {
unregisterReceiver(mMinuteTickReceiver);
mMinuteTickReceiver = null;
}
super.onDestroy();
}
private void registerOnTickReceiver() {
mMinuteTickReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent){
Intent timeTick=new Intent(WidgetProvider.ACTION_TICK);
sendBroadcast(timeTick);
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(mMinuteTickReceiver, filter);
}
}
RepeatingJob class
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class RepeatingJob extends JobService {
private final static String TAG = "RepeatingJob";
#Override
public boolean onStartJob(JobParameters params) {
Log.d(TAG, "onStartJob");
Intent intent=new Intent(WidgetProvider.JOB_TICK);
sendBroadcast(intent);
return false;
}
#Override
public boolean onStopJob(JobParameters params) {
return false;
}
}
AppWidgetAlarm class
public class AppWidgetAlarm {
private static final String TAG = "AppWidgetAlarm";
private final int ALARM_ID = 0;
private static final int INTERVAL_MILLIS = 240000;
private Context mContext;
public AppWidgetAlarm(Context context){
mContext = context;
}
public void startAlarm() {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MILLISECOND, INTERVAL_MILLIS);
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(WidgetProvider.ACTION_TICK);
PendingIntent removedIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Log.d(TAG, "StartAlarm");
alarmManager.cancel(removedIntent);
// needs RTC_WAKEUP to wake the device
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), INTERVAL_MILLIS, pendingIntent);
}
public void stopAlarm()
{
Log.d(TAG, "StopAlarm");
Intent alarmIntent = new Intent(WidgetProvider.ACTION_TICK);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
}
manifest
<receiver android:name=".services.SlowWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<intent-filter>
<action android:name="CLOCK_TICK" />
</intent-filter>
<intent-filter>
<action android:name="JOB_CLOCK_TICK" />
</intent-filter>
<intent-filter>
<action android:name="SETTINGS_CHANGED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.TIME_SET" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.TIMEZONE_CHANGED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.DATE_CHANGED" />
</intent-filter>
<intent-filter>
<action android:name="android.os.action.DEVICE_IDLE_MODE_CHANGED"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.ACTION_DREAMING_STOPPED" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/slow_widget_info" />
</receiver>
<service
android:name=".services.RepeatingJob"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true"/>
<service android:name=".services.WidgetBackgroundService" />
The code snippets provided by #Nikiforos was a blessing for me, although I've felt into many problems when using them on Android 8, thus I decided to let you know how I've solved my issues. There are two problems related with the snippets provided:
they use BackgroundService which is now forbidden in some cases in Android 8
they use implicit broadcasts which have also been restricted in Android O (you can read about why it happened here)
To address first issue I had to switch from BackgroundService to ForegroundService. I know this is not possible in many cases, but for those who can do the change here are the instructions to modify the codes:
Change the restartAll() function as follows:
private void restartAll(Context context){
Intent serviceBG = new Intent(context.getApplicationContext(), WidgetBackgroundService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// for Android 8 start the service in foreground
context.startForegroundService(serviceBG);
} else {
context.startService(serviceBG);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
scheduleJob(context);
} else {
AppWidgetAlarm appWidgetAlarm = new AppWidgetAlarm(context.getApplicationContext());
appWidgetAlarm.startAlarm();
}
}
Update the onStartCommand() function in your WidgetBackgroundService code:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// for Android 8 bring the service to foreground
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
startForeground(1, buildForegroundNotification("Test 3"));
if(intent != null) {
if (intent.hasExtra("SHUTDOWN")) {
if (intent.getBooleanExtra("SHUTDOWN", false)) {
if(mMinuteTickReceiver!=null) {
unregisterReceiver(mMinuteTickReceiver);
mMinuteTickReceiver = null;
}
stopSelf();
return START_NOT_STICKY;
}
}
}
if(mMinuteTickReceiver==null) {
registerOnTickReceiver();
}
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
Add sendImplicitBroadcast() function to your WidgetBackgroundService:
private static void sendImplicitBroadcast(Context ctxt, Intent i) {
PackageManager pm=ctxt.getPackageManager();
List<ResolveInfo> matches=pm.queryBroadcastReceivers(i, 0);
for (ResolveInfo resolveInfo : matches) {
Intent explicit=new Intent(i);
ComponentName cn=
new ComponentName(resolveInfo.activityInfo.applicationInfo.packageName,
resolveInfo.activityInfo.name);
explicit.setComponent(cn);
ctxt.sendBroadcast(explicit);
}
}
Modify registerOnTickReceiver() function in the following way:
private void registerOnTickReceiver() {
mMinuteTickReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent){
Intent timeTick=new Intent(LifeTimerClockWidget.ACTION_TICK);
// for Android 8 send an explicit broadcast
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
sendImplicitBroadcast(context, timeTick);
else
sendBroadcast(timeTick);
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(mMinuteTickReceiver, filter);
}
Hope it helps!
Use the widget itself as the host for the delayed runnable. Widgets have a postDelayed method.
If the widget is killed and recreated, then also recreate the runnable as part of the basic initialization.
Edit:
The above suggestion was based on the inaccurate assumption that the OP was writing a custom view, not an app widget. For an app widget my best suggestion is:
create a foreground service with ONE icon.
the service manages all widgets and clicking on the notification icon will show the various reminders that are active and/allow them to be managed
There is no correct and fully working answer to widget update every minute. Android OS developer purposely exclude such feature or api in order to save the battery and workload.
For my case, I tried to create clock homescreen appwidget and tried many attempt on alarm manager, service etc.
None of them are working correctly.
For those who want to create Clock Widget, which need update time everyminute precisely.
Just use
<TextClock
android:id="#+id/clock"
style="#style/widget_big_thin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top"
android:ellipsize="none"
android:format12Hour="#string/lock_screen_12_hour_format"
android:format24Hour="#string/lock_screen_24_hour_format"
android:includeFontPadding="false"
android:singleLine="true"
android:textColor="#color/white" />
for digital clock text view and
For Analog Clock
<AnalogClock xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/analog_appwidget"
android:dial="#drawable/appwidget_clock_dial"
android:hand_hour="#drawable/appwidget_clock_hour"
android:hand_minute="#drawable/appwidget_clock_minute"
android:layout_width="match_parent"
android:layout_height="match_parent" />
I've found those code from Google Desk Clock Opensource Project. You may already know Google Clock has such widget which update precisely every minute.
To learn more
Google Desk Clock Opensource Repo
Try this code
Intent intent = new Intent(ACTION_AUTO_UPDATE_WIDGET);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) + 1);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmMgr.setInexactRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), 60 * 1000, alarmIntent);

0 processes and 1 service under Settings, Apps and Running

If I start a service with startService in a Activity I get:
1 processes and 1 service
If I now swipe that Activity away. I.e remove it, I get:
0 processes and 1 service
Why is this? And what is a Process and what is a Service in the Android world?
I use START_STICKY and if I stop the service via Settings, Apps and Running, it is not started again, why?
Update1 some code:
Activity:
startService(new Intent(getApplicationContext(), MyService.class));
Service:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "Starting service");
return(START_STICKY);
}
what is the definition of process in android world? same as defined at any operating system - your application is "alive" from the system's point of view, it has active memory allocation stack, and may run or not Activities, Services and so on...
I think that you struggling your had "how can it be that running process = 0" but services = 1 not making scenes, and you are right.
the running applications display shown from the settings app is not made only for developers, but also for users, I guess that's why most vendors decided to show active tasks as process. basically, in this display - running process = running task.
most application starts only one task (the main activity with the launcher flag starts automatically in that mode). there will be more tasks only if other activities would start explicitly with that flag.
so, if your app have 2 activities that started at new task mode - you'll see "2 process".
if your app not running at all (your process really not alive) - then you won't see the app in the running apps screen.
Turned out to be a bug in KitKat.
(Sometimes I think getting anything done in Android is a big hassle!)
Android Services: START_STICKY does not work on Kitkat
https://code.google.com/p/android/issues/detail?id=63793
Fix in Service:
#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);
}
The Main problem in your case is ur unable to start the service when app closed,that time android OS will kill the service, If you are not able to restart the service then call a alam 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");
}
}

How can we prevent a Service from being killed by OS?

I am using Service in my application and it needs to run until my application is uninstalled, but the problem is it gets killed by OS.
How can we prevent it from being killed by OS? Or if it gets killed can we restart that service again through programmatically?
You may run the service in the foreground using startForeground().
A foreground service is a service that's considered to be something
the user is actively aware of and thus not a candidate for the system
to kill when low on memory.
But bear in mind that a foreground service must provide a notification for the status bar (read here), and that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.
Note: This still does not absolutely guarantee that the service won't be killed under extremely low memory conditions. It only makes it less likely to be killed.
I've been puzzled by the same issue to yours recently.but now,I've found a good solution.
First of all,you should know that, even your service was killed by OS, the onCreate method of your service would be invoked by OS in a short while.So you can do someting with the onCreate method like this:
#Override
public void onCreate() {
Log.d(LOGTAG, "NotificationService.onCreate()...");
//start this service from another class
ServiceManager.startService();
}
#Override
public void onStart(Intent intent, int startId) {
Log.d(LOGTAG, "onStart()...");
//some code of your service starting,such as establish a connection,create a TimerTask or something else
}
the content of "ServiceManager.startService()" is:
public static void startService() {
Log.i(LOGTAG, "ServiceManager.startSerivce()...");
Intent intent = new Intent(NotificationService.class.getName());
context.startService(intent);
}
However, this solution is just available for the situation of your service being killed by GC.Sometimes our service might be killed by user with Programme Manager.In this situation,your prosses will be killed,and your service will never been re-instantiated.So your service can not be restarted.
But the good news is,when the PM kill your service,it will call your onDestroy method.So we can do something with that method.
#Override
public void onDestroy() {
Intent in = new Intent();
in.setAction("YouWillNeverKillMe");
sendBroadcast(in);
Log.d(LOGTAG, "onDestroy()...");
}
The string of "YouWillNeverKillMe" is a custom action.
The most important thing of this method is,don't add any code before send the broadcast.As system will not wait for completion of onDestroy(),you must send out the broadcast as soon as posible.
Then regist a receiver in manifast.xml:
<receiver android:name=".app.ServiceDestroyReceiver" >
<intent-filter>
<action android:name="YouWillNeverKillMe" >
</action>
</intent-filter>
</receiver>
Finally,create a BroadcastReceiver,and start your service in the onReceive method:
#Override
public void onReceive(Context context, Intent intent) {
Log.d(LOGTAG, "ServeiceDestroy onReceive...");
Log.d(LOGTAG, "action:" + intent.getAction());
Log.d(LOGTAG, "ServeiceDestroy auto start service...");
ServiceManager.startService();
}
Hope this will be helpful to you,and excuse my poor written english.
Override method onStartCommand() in your service class and simply return START_STICKY (as suggested by "Its not blank"). That's all you need. If the process that runs your service gets killed (by a low memory condition for example), the Android system will restart it automatically (usually with some delay, like 5 seconds).
Don't use onStart() anymore as suggested in another answer, it's deprecated.
use
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//**Your code **
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
ref Documentation lifecycle of Service.
Edit added method.
As far i know, onDestroy() will be called only when the service is explicitly stopped(Force Stop). But this method won't get called in case the service gets killed by OS/swiping the Recent Apps list. In those cases another event handler named onTaskRemoved(Intent) gets called. This is due to a defect in Android 4.3-4.4 as per the link here. Try using the below code:-
public void onTaskRemoved(Intent intent){
super.onTaskRemoved(intent);
Intent intent=new Intent(this,this.getClass());
startService(intent);
}
I found another solution of the problem which gurantees that your service will be always alive. In my case, this scheme resloves also the problem with FileObserver, which stops work after some period of time.
Use an activity (StartServicesActivity) to start the service (FileObserverService) as Foreground service.
Use BroadcastReceiver class (in example CommonReceiver) to restart your service in some special situations and in case it was killed.
I used this code in my app "Email Pictures Automatically"
https://play.google.com/store/apps/details?id=com.alexpap.EmailPicturesFree
Here is CommonReceiver class.
public class CommonReceiver extends BroadcastReceiver {
public void onReceive(Context paramContext, Intent paramIntent)
{
paramContext.startService(new Intent(paramContext, FileObserverService.class));
}
}
Here is its definition in AndroidManifest.xml just before application closing tag.
<receiver android:name="com.alexpap.services.CommonReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.USER_PRESENT"/>
</intent-filter>
</receiver>
Start service in StartServicesActivity activity.
Intent iFileObserver = new Intent(StartServicesActivity.this, FileObserverService.class);
StartServicesActivity.this.startService(iFileObserver);
Here is onStartCommand() method of the service.
public int onStartCommand(Intent intent, int flags, int startId) {
int res = super.onStartCommand(intent, flags, startId);
/*** Put your code here ***/
startServiceForeground(intent, flags, startId);
return Service.START_STICKY;
}
public int startServiceForeground(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, StartServicesActivity.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("File Observer Service")
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
startForeground(300, notification);
return START_STICKY;
}
I tested this code using Task Killer app, and each time the service was killed, it was restarted again almost immediately (performs onStartCommand()). It is restarted also each time you turn on the phone and after rebooting.
I use this code in my application, which emails every picture you take with your phone to predefinde list of emails. The sending email and list of receiving emails are set in another activity and are stored in Shared Preferences. I took about 100 pictures in several hours and all they were sent properly to receiving emails.
#Override
public void onDestroy() {
super.onDestroy();
startService(new Intent(this, YourService.class));
}
write above code in your service and your service will never stop even user want to destroy it or they want to kill it it will never kill untill your app not get uninstall from your device
You can try to start your service repeatedly, for example every 5 sec.
This way, when your service is running, it will perform onStartCommand() every 5 sec. I tested this scheme and it is very reliable, but unfortunately it increases slightly phone overhead.
Here is the code in your activity where you start the service.
Intent iFileObserver = new Intent(StartServicesActivity.this, FileObserverService.class);
PendingIntent pendingIntentFileObserver = PendingIntent.getService(StartServicesActivity.this, 0, iFileObserver, 0);
AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
Date now = new Date();
//start every 5 seconds
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, now.getTime(), 5*1000, pendingIntentFileObserver);
And here is onStartCommand() of the service.
//class variable
public static boolean isStarted = false;
public int onStartCommand(Intent intent, int flags, int startId) {
int res = super.onStartCommand(intent, flags, startId);
//check if your service is already started
if (isStarted){ //yes - do nothing
return Service.START_STICKY;
} else { //no
isStarted = true;
}
/**** the rest of your code ***/
return Service.START_STICKY;
}
First create service in another process, and write broadcaster which runs in recursion in time intervals
protected CountDownTimer rebootService = new CountDownTimer(9000, 9000) {
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
sendBroadcast(reboot);
this.start();
Log.d(TAG, "rebootService sending PREVENT AUTOREBOT broadcast");
}
};
After that register broadcast receiver in main process also with timer recursion that is launched after first broadcast from service arrived
protected static class ServiceAutoRebooter extends BroadcastReceiver {
private static ServiceAutoRebooter instance = null;
private RebootTimer rebootTimer = null;
private static ServiceAutoRebooter getInstance() {
if (instance == null) {
instance = new ServiceAutoRebooter();
}
return instance;
}
public class RebootTimer extends CountDownTimer {
private Context _context;
private Intent _service;
public RebootTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
_context.startService(_service);
this.cancel();
Log.d(TAG, "Service AutoRebooted");
}
}
#Override
public void onReceive(Context context, Intent intent) {
if (rebootTimer == null) {
Log.d(TAG, "rebootTimer == null");
rebootTimer = new RebootTimer(10000, 10000);
rebootTimer._context = context;
Intent service = new Intent(context, SomeService.class);
rebootTimer._service = service;
rebootTimer.start();
} else {
rebootTimer.cancel();
rebootTimer.start();
Log.d(TAG, "rebootTimer is restarted");
}
}
}
Service will be auto-rebooted if time at RebootTimer (main process) expires, which means that "PREVENT AUTOREBOT" broadcast from service hasn't arrived
i found a solution .... late answer but i wanted to answer...
we can send a broadcast in the ondestroy of the service and create a receiver that receives the broadcast and starts the service again.... when it is destroyed by any reasons...
pls try following:
final Messenger mMessenger = new Messenger(new IncomingHandler());
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
default:
super.handleMessage(msg);
}
}
}
#Override
public void onCreate() {
super.onCreate();
makeServiceForeground();
}
#Override
public IBinder onBind(Intent arg0) {
return mMessenger.getBinder();
}
private void makeServiceForeground() {
IActivityManager am = ActivityManagerNative.getDefault();
try {
am.setProcessForeground(onBind(null), android.os.Process.myPid(), true);
} catch (RemoteException e) {
Log.e("", "cant set to foreground" + e.toString());
}
}
also need add in manifest.xml
<uses-permission android:name="android.permission.SET_PROCESS_LIMIT"/>

Categories

Resources