I have an android app with service that has to track user's location even with closed application only if user set flag in app. So I start service in code after user clicks button and stop when he clicks it again with following code
alarm.changeAlarmStatus();
if(alarm.getAlarmStatus()) {
SharedPreferences.Editor ed = alarmPreferences.edit();
ed.putFloat("MARKER_LATITUDE", (float) theMarker.getPosition().latitude);
ed.putFloat("MARKER_LONGITUDE", (float) theMarker.getPosition().longitude);
ed.commit();
startService(myIntent);
}
else{
stopService(myIntent);
}
It seems to work fine. Service works and does what it should. But problem is if I close application through the task manager I see in logcat that Service starts again(but only if service is already working) and it causes nullPointerException because intent is null. You can see in this code why it happens
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Bundle bundle = intent.getExtras();
alarm = (Alarm) bundle.getSerializable("alarm");
Log.d("service","On Start Command is called ");
serviceIntent = intent;
return START_STICKY;
}
However I need to start my service only by pressing button and no other way. Does anyone know how to fix that?
Return START_NOT_STICKY in onStartCommand instead of START_STICKY.
If START_STICKY is returned, system will try to re-create service after it is killed.
If START_NOT_STICKY is returned, system will not try to re-create service after it is killed.
Related
I have two Application A and B.In app B I have a service that I can run it from app A. I want to send data to app B with intent but always my intent is null!
I run app B's service from app A with this Code:
try {
String packageName = "app_B_package";
String appService = packageName + ".activity.InternetService";
Intent start = new Intent();
start.setComponent(new ComponentName(packageName, appService));
start.putExtra("LAUNCHER_COMMAND_CLOSE" , true);
G.context.startService(start);
} catch (Exception e) {
e.printStackTrace();
}
But when service of app B will run the intent is null. This is onStart of the service in app B:
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Log.i("LOGO_OFFICE_IN", "onStart");
if (intent != null) {
if (intent.getExtras().getBoolean("LAUNCHER_COMMAND_CLOSE")) {
Tools.clearApplicationData(InternetService.this);
new AppStatus(InternetService.this).isAppRunning(getPackageName(), true);
}
}
}
Why my intent is null all the time? I can't find it out.
Thank you for your help.
It looks like your service is type fire-and-forget - it does one quick thing and should quit immediately because it's done. Correct?
1. Don't leave your idle service running
Documentation says
If a component starts the service by calling startService() (which results in a call to onStartCommand()), the service continues to run until it stops itself with stopSelf() or another component stops it by calling stopService().
so after your workload is done call stopSelf().
When your service is not running there's nothing to restart.
2. Use correct start mode
Unless you stop it, your service is by default automatically restarted after it's killed by system (because system needed resources). The default mode is called START_STICKY and does this:
This mode makes sense for things that will be explicitly started and stopped to run for arbitrary periods of time, such as a service performing background music playback.
Since your service is a quick one-time job, it makes no sense for it do be restarted later at an arbitrary time.
To let Android know, you should return START_NOT_STICKY from onStartCommand.
3. Use current API
Don't use onStart, it was deprecated 9 years ago. It doesn't support start modes mentioned above. Implement onStartCommand instead. Your service would look like this:
#Override
public void onStartCommand(Intent intent, int flags, int startId) {
// No super call.
Log.i("LOGO_OFFICE_IN", "onStart");
// Intent cannot be null.
if (intent.getExtras().getBoolean("LAUNCHER_COMMAND_CLOSE")) {
Tools.clearApplicationData(InternetService.this);
new AppStatus(InternetService.this).isAppRunning(getPackageName(), true);
}
stopSelf(); // Work is done, stop service.
return START_NOT_STICKY; // Don't restart if killed.
}
Now that I think of it, only step 1 is absolutely necessary. Anyway, get into habit of using current APIs and finding out how things work.
I am building an application using PhoneGap, which revolves around a timer I have created. I am struggling at the moment as I need a way of having the app open itself if the timer reaches zero. I have currently put in place a notification for when the timer runs out, and the user can launch the app from there. However I need a way of launching the app if the user "misses" the notification or something similar.
For example, when the timer on the local "timer" app on a mobile device runs out, it will open itself to notify the user that the time has ran out.
Any suggestion would be appreciated,
Thanks.
Just write the code for opening the launcher Activity instead of showing notification in your service class.When the timer runs out the launcher activity will start instead of notification.
the code will look similar to this:
public class AlarmService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//calling Launcher Activity
Intent alarmIntent = new Intent(getBaseContext(), AlarmScreen.class);
alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
alarmIntent.putExtras(intent);
getApplication().startActivity(LauncherActivity.class);
AlarmManagerHelper.setAlarms(this);
return super.onStartCommand(intent, flags, startId);
}
}
I hope you are satisfied with this answer.
i have troubles with my STICKY Service. I call it in my MainActivity.class and bind it:
MainActivity:
Intent intent = new Intent(this, MyService.class);
ComponentName MyCompName= startService(intent);
bindService(intent, MyConnection, Context.BIND_AUTO_CREATE);
and...
MyService
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
I want that this Service runs STICKY and never be closed or restarted. But when i close my Application, the onCreate()-Method of MyService is called and all variables are reseted, and i don´t know why.
BTW: I don´t call stopService!
The difference between STICKY and NON_STICKY services is that STICKY services are restarted after being killed. I don't think it's possible to guarantee that your service will never be restarted - if memory is low it might be restarted.
If you need to preserve the state, you can save variables in a database. To see if the service is being created for the first time or restarted, you can check if the intent in onStartCommand is null.
If you only need to preserve the initial state when the service was created, you can use START_REDELIVER_INTENT which will resend the Intent used to create the service in onStartCommand.
I noticed that Service.START_STICKY doesn't work and when I tokk a closer look, I saw the onCreate() is running but onStartCommand is not called.
Any ideas why?
#Override
public void onCreate() {
mGlobalData = GlobalData.getInstance();
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (mTimer == null)
mTimer = new Timer();
Log.e(TAG, "onCreate()");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
int t = START_STICKY;
Log.e(TAG, "call me redundant BABY! onStartCommand service");
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return t;
}
If you have the same situation I had, my Service starts up and runs just fine (onCreate() and onServiceConnected() are both invoked) but onStartCommand(Intent,int) was never called. I found it's because the system started my Service instead of me explicitly starting the Service in code. According to the docs:
[onStartCommand(Intent,int) is] called by the system every time a client explicitly starts the service by calling startService(Intent)
So I had to call startService(new Intent(context, MyService.class)) explicitly in code to get onStartCommand(Intent,int) to trigger. Note that doing this will not restart the Service created by the system and it won't create a new instance of that Service either.
Try to insert the line android.os.Debug.waitForDebugger(); at the end of onCreate(). The debugger didn't reach onStartCommand()'s breakpoints for me until I did this.
Application thread get close if its killed by task manager. Need to re-invoke application as though its killed by other application or task manager. Any idea?
You have to run background service with START_STICKY command.
Just extends Service and override onCommand like this :
#Override
public int onStartCommand(Intent intent,int flags,int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
Like this your Service is restart when it's close (by system or anything else)
You just have now check on your service (onCreate for example) if application is running or not and launch it again if not. I suppose PackageManager let you check this or simply put a static boolean is_alive to see if your activity is always running.
Regards
Jim
Bug in Android 2.3 with START_STICKY
I needed to keep alive a Service with all my forces. If the service is running anytime you can pop the UI.
onDestroy()
it will re-launch.
Can't be uninstalled the app, because it has a Device Administrator.
It is a kind of parental control, the user knows it is there.
Only way to stop is to remove the Device Admin, and uninstall it, but removing Device Admin will lock the phone as Kaspersky how it does.
There are a loot of braodcast receivers, such as boot finshed, user presen, screen on, screen off... , many other, all starting the service, you can do it with UI too. Or in the service check if your activity alive , visible, if not, than pop it.
I hope you will use with good reason the info!
Edit: Restart service code snippet:
// restart service:
Context context = getApplicationContext();
Intent myService = new Intent(context, MyService.class);
context.startService(myService);
Edit2: add spippet to check if the service is running in ... a load of Broadcasts
public static boolean isMyServiceRunning(Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (MyService.class.getName().equals(service.service.getClassName())) {
Log.d("myTag", "true");
return true;
}
}
Log.d("myTag", "false");
return false;
}
Edit3 other service start:
public static void startTheService(Context context) {
Intent myService = new Intent(context, MyService.class);
context.startService(myService);
}
Dont't forget Android 2.3 bug: do the logic for initialization in
#Override
public void onCreate()
and not in:
#Override
public int onStartCommand(Intent intent, int flags, int startId)
While look at Google IO official product source code I have found the following
((AlarmManager) context.getSystemService(ALARM_SERVICE))
.set(
AlarmManager.RTC,
System.currentTimeMillis() + jitterMillis,
PendingIntent.getBroadcast(
context,
0,
new Intent(context, TriggerSyncReceiver.class),
PendingIntent.FLAG_CANCEL_CURRENT));
URL for code
You can start a sticky service and register an alarm manager that will check again and again that is your application is alive if not then it will run it.
You can also make a receiver and register it for <action android:name="android.intent.action.BOOT_COMPLETED" /> then you can start your service from your receiver. I think there should be some broadcast message when OS or kills some service/application.
Just to give you a rough idea I have done this and its working
1) register receiver
Receiver Code:
#Override
public void onReceive(Context context, Intent intent) {
try {
this.mContext = context;
startService(intent.getAction());
uploadOnWifiConnected(intent);
} catch (Exception ex) {
Logger.logException(ex);
Console.showToastDelegate(mContext, R.string.msg_service_starup_failure, Toast.LENGTH_LONG);
}
}
private void startService(final String action) {
if (action.equalsIgnoreCase(ACTION_BOOT)) {
Util.startServiceSpawnProcessSingelton(mContext, mConnection);
} else if (action.equalsIgnoreCase(ACTION_SHUTDOWN)) {
}
}
Service Code:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Logger.logInfo("Service Started onStartCommand");
return Service.START_STICKY;
}
I prefer doing nothing in onStartCommand because it will get called each time you start service but onCreate is only called 1st time service is started, so I do most of the code in onCreate, that way I don't really care about weather service is already running or not.
according to #RetoMeyer from Google, the solution is to make the app "sticky".
for this, you must establisH START_STICKY in your intent service management.
check this reference from developer android
Yes, Once memory low issue comes android os starts killing application to compensate the required memory. Using services you can achieve this, your service should run parallely with your application but see, some of the cases even your service will be also killed at the same time. After killing if memory is sufficient android os itself try to restart the application not in all the cases. Finally there is no hard and fast rule to re-invoke your application once killed by os in all the cases it depends on os and internal behaviours.