What I am trying to do is once the AppWidget is removed from the homescreen of the user's Android phone, I want to stop the background service that Updates the AppWidget.
Here is the code that I am using...don't understand whats wrong?
#Override
public void onDeleted(Context context, int[] appWidgetIds){
Intent serviceIntent = new Intent(context, UpdateService.class);
context.stopService(serviceIntent);
super.onDeleted(context, appWidgetIds);
}
Any ideas? Thanks for the help.
After a lot of Research I finally fixed it. My goal here was to stop the background service if all AppWidget instances are removed from the screen.
This is what did it...
Used shared preferences to toggle 1 and 0. SharePref toggled to 1 when the very first instance of the widget is put on the screen by the user. It is toggled back to 0 when the last instance of the App widget is removed from the screen.
#Override OnReceive method in the Service. Listen for these broadcasts - AppWidget Enabled (broadcast when the very first instance of the widget is put on the screen) , AppWidget Disabled (broadcast by the OS when the very last instance of the widget is removed from the screen)
When AppWidget Disabled is broadcast call the overridden method OnDisabled method.
3.In #Override OnDisabled method call stopService. Works perfect.
Remember the difference between OnDeleted and OnDisabled. OnDeleted is called when an instance of the widget is removed, it doesn't mean that the widget being deleted is the last one. I wanted my service to still run even if there was a single widget instance on the screen.
*Also if you do not want to do all of the above and let Android take care of the Service etc...use IntentService. **
I think the stopservice is calling onDestroy in the Service itselfs.
It works for me with the following code in the Service
#Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
//Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
}
timer ist the timer which i am starting in the _startService void
Related
I am confused right now , about service concept of running and stopping:
what i want to do:
Start Location service at the very start of application.
Keep getting location updates and store them to shared preference
Stop the service in onDestroy of Application scope!
So far i have searched and studied we can only do following things with service(correct me if i'm wrong):
Stop the service automatically by binding it to related activities/fragments/views , when all of them destroyed service unbind itself automatically so we can call stopself method in unbind
return START_NOT_STICKY in onStartCommand to tell OS , don't recreate it , and create intent local service , after completion of some work it will destroy itself.
Stopping the service manually , by declaring it's intent in some kind of static scope and stopping the service in on onActivityDestroyed of Application class [I am not sure what will happen? , maybe service will destroy each time any activity will be destroyed ? or it will be destroyed only when overall application get's destroyed?]
Either way , i am bit confused and beat , been trying to adjust my Location service with given details for 2 days
If you start your Service using START_NOT_STICKY, then your app will kill your service once your entire application is closed from background i.e. you cleaned your app from home screen.
Here START_NOT_STICKY states that you need not recreate service in case it is been killed.
If this is not the case then you have to manually kill it by your self.
Like
Intent lintent = new Intent(context, LocationService.class);
context.stopService(lintent);
You can use this code at point where your application kills.
That's it. You are good to go with this.
First of all, launch the "LocationService" on your app start:
public class MyApp extends Application {
private static final String TAG = "MyApp";
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "App started up");
startService(new Intent(this, MyLocationService.class));
}
}
Second :
As you said, the Service should better run with the "START_NOT_STICKY" flag
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
Thrid:
Once the system kills your app, the Service will automatically be killed, so no problems at all.
There is no onDestroy() method on the Application object, the only similar event is onTerminated() and it is not being launched on production devices.
onTerminate
Added in API level 1 void onTerminate () This method is for use in
emulated process environments. It will never be called on a production
Android device, where processes are removed by simply killing them; no
user code (including this callback) is executed when doing so.
More information:
https://developer.android.com/reference/android/app/Application.html#onTerminate()
Btw, If you want the MyLocationService to send updates of the location to your app (when it is open), you should consider to use Otto or EventBus (I recommend you this last one because of the simplicity to use it). You can even configure the #Suscriber to receive updates of old retrieved locations if you want.
I will try to explain in a easiest way :)
There are two type of service
IntentService and Service
IntentService when started will kill itself once it treated the content of it onHandleIntent method
as for Service well this one will not end until you give it the command to do so even if your start it using the context of an activity. It will also stop when the application is stopped in an extreme case (by system (Settings/application/YourApp/stop app OR an app crash)
Easiest way is First of all start IntentService with AlarmManager at some repeating time (10 mintutes), then in onHandleIntent() get Location and store into preference.
No Need bind to your activity, the IntentService automatically stops itself after saved in preferences.
Yes you can stop the service in onDestroy() of the activity:
#Override
public void onDestroy(){
Log.v("SERVICE","Service killed");
service.stop();
super.onDestroy();
}
I have a service which I start using
Intent serviceIntent = new Intent(getActivity().getApplicationContext(), LocationService.class);
getActivity().startService(serviceIntent);
When app is going into background, not closed, just not in foreground: i.e. press home button, I do:
Notification notification = mBuilder.build();
service.startForeground(NOTIFICATION, notification);
To bring the service to the foreground and show ongoing notification.
I have a BroadcastReceiver which is fired when the notification's shut down action is clicked (added action to notification).
The BroadcastReceiver stops the service:
#Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context.getApplicationContext(), LocationService.class);
context.stopService(serviceIntent);
}
Now, there are two scenarios:
When app goes to background but not closed!, when pulling down the notification bar and clicking the shut down action -> the service's onDestroy is called just fine. I can see Toast and Log messages from onDestroy.
When app is closed (swiped away from apps list), meaning only service is running, when pulling down the notification bar and clicking the shut down action -> it doesn't look like the service's onDestroy is called! The code over there is not executed, and I cant see Toast and Log messages from onDestroy.
However, it seems that the service does stop, because I can see the app removed from settings -> running apps after clicking the shut down.
So, is the service getting destroyed? and if so, why isn't the code in onDestroy gets executed?
How can I make sure onDestroy is called?
Obviously it has something to do with the fact that in "good" scenario, the app is still in the background, and in the "bad" scenario, the app is closed.
EDIT:
Thanks to CommonsWare's and John Leehey's comments, I understood that it could be that the "process is being terminated" and "there is no guarantee" that onDestory() will be called.
My onDestory looks like this:
#Override
public void onDestroy() {
super.onDestroy();
stopLocationUpdates();
googleApiClient.disconnect();
Foreground.get(this).removeListener(this);
// set default zoom
sharedPrefrencesManager.putFloat(getString(R.string.zoom_last_location_key), 15);
Log.i("test", "onDestroy");
}
Should I do the stuff like stopLocationUpdates(); and googleApiClient.disconnect(); in another place? since there is no guarantee of onDestory being called?
I'm using a running service to detect whether network is available or not. When it is not available, it calls an activity to start that displays a blank screen with "no network available" on it. When the network is back, it sends a broadcast to finish this activity.
The only problem is that this activity may start at any time (as a popup), even when using other apps. I want it to start (or be visible) only if the network is out and my app is in the foreground. Any help?
One option would be to have your foreground activity register for the broadcast, and then display the relevant notification from within the activity.
Alternatively you could start your service when your foreground activity starts/resumes (i.e, onResume), and stop it when your activity leaves the foreground.
You can use START_STICKY in your service to ensure it stays around until you stop it, like so:
#Override
public int onStartCommand(Intent intent, int flags, int startId){
//On start work here
return START_STICKY;
}
and then stop the service using stopService when your activity leaves the foreground (i.e onPause).
If you need the former behaviour across multiple activities you can register broadcast receivers programmatically:
BroadcastReceiver myBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(MY_ACTION.equals(intent.getAction()))
{
//show appropriate dialog
}
}
};
IntentFilter myIntentFilter = new IntentFilter();
myIntentFilter.addAction(MY_ACTION);
registerReceiver(myBroadcastReceiver,myIntentFilter);
You can unregister like so:
unregisterReceiver(myBroadcastReceiver);
You could extend Activity and make your own custom subclass that reuses similar code to register and unregister whilst entering/leaving the foreground. Or you can extract this into utility methods/classes and call from the appropriate places.
I think you need Shared Preference to do this. store one Boolean value on finish you activity (you can use onpause() or onStop()) and for showing popup check the value and do what you want
for understnding to use sharePreference see this and developer.android.com
Try the following:
Intent intent = new Intent(this, YourActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
This worked in the context of my own app already running, I'm not sure if it will start your app if it is not already running in the background
EDIT: Not sure if I understand your question entirely. If you only want this activity to come to the foreground while your app is in the foreground, get rid of the addFlags line, also you can do some boolean stuff to check if your app is in the foreground like so, this way your code won't even run if the app isn't in the foreground.
EDIT: There are a few ways to check if your app is in the foreground, the link I posted above has one such solution, another one is to create a static boolean isForeground variable: in the onResume() methods of your app set isForeground = true and in onPuase() set isForeground = false. This isn't the best practice, using ActivityManager is better, but for purposes of testing this should be ok.
Then have something like the following:
if(isForeground){
//Start your activity
}
This should be quick to write, if this is the behavior you want, I would recommend replacing the isForeground static variable with the test for foreground provided by ActivityManager in the link I posted.
I have a question regarding Android widgets and especially Android services. Here is what I want to do: On the phone the user should be able to add my widget to his homescreen. The widget gets its data from network.
After reading some tutrials about this, I found out that the best approach would be to create a service that gets the data from network (TCP sockets) and then updates the widget constantly. That is done with ScheduledExecutorService which executes a Runnable in a certain interval.
The Runnable will connect to a server, get the data and should update the widget).
My problem is now, that the widget don't need to be updated when the screen is off and so the service should not run because of battery drain. My question is: How to do it the best way?
I found 2 approaches which would more or less do what I want:
When the first instance of the widget is added to homescreen, it will register a Broadcast Receiver that receives the ACTION_SCREEN_ON and ACTION_SCREEN_OFF intent action from Android OS.
If ACTION_SCREEN_ON is fired, it will start the updater service, otherwise it will stop it. But I'm really unsure if that's a good approach because of the broadcast receiver lifetime.
In the updater service's Runnable, which is executed periodically by the ScheduledExecutorService and actually does the network stuff, I check via PowerManager.isScreenOn(), if the screen is on. If yes, I execute the network code, otherwise not. But what is when the device is in standby? Is this code executed then? What about battery drain here?
Is there maybe a "best practice" approach for what I want to do? I've read alot about the AlarmManager and that it is a very powerful tool. Can you schedule tasks with this in the way, that they are only executed when the display is on?
Thanks for your help.
Best Regards
NiThDi
Your first solution (widget handling screen ON and OFF broadcasts) to the problem is the way to go. Start a new IntentService for a background communication to your application server. Once it finished, send your custom "Completed" broadcast with results and then handle it in your widget.
As an additional benefit it would allow multiple instances of your widget to work from one "source" and would not consume any resources in case user did not add any widgets.
UPDATE As it is impossible to use screen ON/OFF broadcasts with a widget, I would probably use this (AlarmManager with an ELAPSED_REALTIME (not ELAPSED_REALTIME_WAKEUP) alarm) to schedule an (intent) service run. This way your service will not be scheduled when screen is off, but will run periodically when it is on. And if the delay between screen ON and OFF is more than the period it will run immediately on screen coming back ON.
As for your question about broadcast receivers lifetime, as said before, use IntentService for a long running task and then broadcast your results back from it. When you starting a service that call does not block so broadcast receiver will finish in a timely matter.
UPDATE 2 According to this screen OFF does not mean device is sleeping. You already have a solution to this issue by using PowerManager.isScreenOn().
The ELAPSED_REALTIME approach could work I think, but strangly it is not for a small test app I created.
Basically the test app is a widget and a IntentService. The widget only shows the current time, while the Intent Service gets the current time and sends a broadcast which the widget consumes in the onReceive() method and updates itself. The widget is of course a registered receiver for the custom broadcast action.
In the onEnabled() method in the widget, I initialize the alarm for AlarmManager. Now some code:
Widget onEnabled():
#Override
public void onEnabled(Context c) {
super.onEnabled(c);
Intent intent = new Intent(c.getApplicationContext(), SimpleIntentService.class);
PendingIntent intentExecuted = PendingIntent.getService(c.getApplicationContext(), 45451894, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) c.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, 0, 3000, intentExecuted);
}
Widget onReceive():
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if (intent.getAction().equals(ACTION_RESP)) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName thisWidget = new ComponentName(context.getApplicationContext(), Widget.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
for (int appWidgetId : allWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getApplicationContext().getPackageName(), R.layout.widget);
String s = "";
if (intent.hasExtra("msg")) s = intent.getStringExtra("msg");
// Set the text
remoteViews.setTextViewText(R.id.textView1, s);
appWidgetManager.updateAppWidget(allWidgetIds, remoteViews);
}
}
}
SimpleIntentService onHandleIntent():
#Override
protected void onHandleIntent(Intent intent) {
Log.w("TestService", "SimpleIntentService onHandleIntent called.");
String msg = new Date().toGMTString();
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(Widget.ACTION_RESP);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra("msg", msg);
sendBroadcast(broadcastIntent);
}
So, I have tested this on my Nexus 4 running Android 4.2.1 and on an emulator with Android 4.0.4. In both cases the SimpleIntentService gets created and onHandleIntent() gets called every 3 seconds, even when I manually turn the display off.
I have absolutely no idea why the AlarmManager still schedules the alarm, do you have?!
Thank you!
I have a widget that, when pressed, sends a broadcast that starts a CountDownTimer that updates my widget, and at the end plays an alarm. This works beautifully in the emulator.
On my phone, however, it's a different story. My phone is so resource constrained that my process is killed regularly, which, of course, means that the CountDownTimer no longer updates my widget.
It seems to be that the only way to reliably do stuff in the future is to use the AlarmManager, as this sets a system-level alarm. However, the documentation states, and I agree, that you're not supposed to use it for ticks. However, since anything else you're likely to use has the possibility of being shut down arbitrarily, they're not really giving us much choice.
My question is: is there a way to ensure that a CountDownTimer keeps ticking and finally calls onFinish(), or do I have to simply drop it and switch to AlarmManager, and "misuse" it? Any other options of guaranteeing that the thing ticks and finishes are also welcome.
I should add that I can't rely on the OS calling onUpdate(), both because it will do so no faster than every 30 minutes, and also because most of the time the widget just does nothing. It's only when it is clicked that it ticks down every second for a handful of minutes.
I think this is a solution.. Create a dummy service..
public class DummyService extends Service{
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
and start it from your activity using countdowntimer like this.. in oncreate of the activity
Intent intent = new Intent(this, DummyService.class);
startService(intent);
and also dont forget to declare this service in your manifest like this..
<service android:name=".DummyService" >
</service>
hope this helps..
What I ended up doing was moving from a BroadcastReceiver to a Service.
Not just using a dummy service, but having a real service embody what the BroadcastReceiver did previously.
As this won't guarantee that my timers won't get killed, if requested, android will automatically try to restart your service after it's been killed. In this event, I plan to have some code that will restore the running state from disk and continue.
To add to the accepted answer: from what I remember, the BroadcastReceiver only lives as long as it takes to process the broadcast.
So launching a timer or something from within the BroadcastReceiver will not work (as stated).
This is why it is recommended to use the BroadcastReceiver to launch a Service that will do the timing. Sure, the service can still be killed, but not as early as the BroadcastReceiver.