I'm developing an Air (Flex) Mobile application for Android, which uses Air Native Extension (ANE) to take advantage of some platform functions that otherwise could not be used (at least to my knowledge). One of the platform functions that I want to use are services, specifically services that run as Foreground processes (using the startForeground() method).
When I invoke the service from my ANE everything works like a charm, the service is started correctly and it does what it needs to do but the problem is that Android seems to be trying to start it independently from my code, which, of course, results in errors that appear in the LogCat.
When I launch the application in debug mode in Flash Builder, and I use it for a while checking that the service works perfectly and no errors are thrown, after I close it from the Flash Builder (not from Eclipse ADT, which I also could) a couple of seconds later, the following errors appear:
01-16 10:56:06.953: E/AndroidRuntime(9757): java.lang.RuntimeException: Unable to start service com.mycompany.myextension.services.MyService#41594a50 with Intent { cmp=air.QOE.debug/com.mycompany.myextension.services.MyService }: java.lang.NullPointerException
01-16 10:56:06.953: E/AndroidRuntime(9757): at com.mycompany.myextension.services.MyService.onStartCommand(MyService.java:37)
It seems to be clear that Android tries to start the service but since its design to work inside the ANE -the extension is initialized but its context was already disposed- it crashes because it cannot reach the variables that are initialized within the context, therefore, ending in a crash or error the first time the code uses a context variable (line 37).
I would think that this has to do with the way I declared the service in my Android Manifest file. Next is part of the XML:
<application android:debuggable="true">
<service android:enabled="true" android:exported="true" android:name="com.mycompany.myextension.services.MyService">
<intent-filter>
<action android:name="air.com.mycompany.myextension.DO_CUSTOM_ACTION"/>
</intent-filter>
</service>
</application>
I hope you can tell me if I’m declaring the service incorrectly or if I’m making a mistake elsewhere. I appreciate the help.
EDIT: Service code
package com.mydomain.myapplicationextension.services;
import java.util.Timer;
import com.adobe.fre.FREContext;
import com.mydomain.myapplicationextension.myapplicationextension;
import com.mydomain.myapplicationextension.components.HttpServiceTask;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
public class MyApplicationService extends Service {
private Timer timer;
#Override
public IBinder onBind(Intent arg0) {
// Log.d("MyApplicationService", "onBind()");
return null;
}
#Override
public void onCreate() {
// Log.d("MyApplicationService", "onCreate()");
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Log.d("MyApplicationService", "onStartCommand(): " + myapplicationextension.applicationID);
Context appContext = myapplicationextension.applicationContext;
Intent launchIntent = appContext.getPackageManager().getLaunchIntentForPackage(myapplicationextension.appPackageName);
PendingIntent pendingLaunchIntent = PendingIntent.getActivity(appContext, 0, launchIntent, 0);
FREContext extContext = myapplicationextension.extensionContext;
int icon = extContext.getResourceId("drawable.notification_icon");
Notification notification = new Notification.Builder(appContext)
.setContentTitle(myapplicationextension.applicationID)
.setContentText(myapplicationextension.notificationMessage)
.setSmallIcon(icon)
.setContentIntent(pendingLaunchIntent)
.build();
startForeground(1,notification);
// Log.d("MyApplicationService", "startForegroundService()");
if(myapplicationextension.checkStatus)
{
timer = new Timer("Printer");
HttpServiceTask serviceTask = new HttpServiceTask(timer, launchIntent,myapplicationextension.statusServiceURL, myapplicationextension.triggerResponse);
timer.schedule(serviceTask, 0, 2000);
// Log.d("MyApplicationService", "startTimer()");
}
return START_STICKY;
}
#Override
public void onDestroy() {
// Log.d("MyApplicationService", "onDestroy():");
if(myapplicationextension.checkStatus)
{
timer.cancel();
timer = null;
// Log.d("MyApplicationService", "onDestroy(): timer.cancel():");
}
super.onDestroy();
}
}
When the phone runs out of memory and kills the service before it finishes executing. START_STICKY tells the OS to recreate the service after it has enough memory and call onStartCommand() again with a null intent. START_NOT_STICKY tells the OS to not bother recreating the service again. There is also a third code START_REDELIVER_INTENT that tells the OS to recreate the service AND redelivery the same intent to onStartCommand().
START_STICKY and START_NOT_STICKY
I have an ANE using START_STICKY that keeps launching the service
Related
I noticed some very strange behavior when testing foreground notifications on Android 9.
Situation: I have some foreground services where I don't know how long they'll need to run for, be it 1 second or a whole minute. Finally, when the service is done, it will call stopForeground(true). This used to work fine on all Android 8, 9 and 10 devices, where stopForeground(true), even if called immediately, always reliably removed the notification.
Problem: Testing on a Fairphone 3 (and I hope someone else encountered this on some other devices, because for me this is not happening on any emulator or other device), stopForeground is not working as expected. Instead of immediately removing the notification, the notification always shows for at least 5 seconds, even if I call stopForeground straight away. These 5 seconds happen to be the exact 5 second limit of the dreaded error Context.startForegroundService() did not then call Service.startForeground() - still a problem. Very peculiar! Reproducing this and checking whether your device is affected is very easy with the code below.
Inside AndroidManifest.xml:
<service
android:name="<your package name>.TestService"
android:exported="false" />
Class TestService.java:
package <your package name>;
import android.annotation.TargetApi;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
#TargetApi(Build.VERSION_CODES.O)
public class TestService extends Service {
#Override
public void onCreate() {
super.onCreate();
showNotification();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
showNotification();
stopForeground(true);
return super.onStartCommand(intent, flags, startId);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void showNotification() {
String channelId = "TEST";
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager.getNotificationChannel(channelId) == null)
notificationManager.createNotificationChannel(new NotificationChannel(channelId, "TEST NOTIFICATIONS", NotificationManager.IMPORTANCE_DEFAULT));
startForeground(1, new NotificationCompat.Builder(this, channelId).setContentText("TEST NOTIFICATION").build());
}
}
Finally, simply start the service (for example on button click) via startForegroundService(new Intent(this, TestService.class));
Has anyone else experienced this issue or is able to reproduce it with the code above? How can I fix or even just debug it, considering I'm testing on Android 9 and the behaviour is different simply because of the OEM?
Latest security patch claims that it's normal behaviour:
https://issuetracker.google.com/issues/147792378
However I'm not sure why it's happening already on Android 9.
I'm posing this as Q&A style because I found this idea working. And it's a fix to the hard problem to crack for beginners with Android.
Google has deprecated registering Broadcast Receiver into manifest like this below from API Level 26+ ( Except Some )
<receiver android:name=".MyBroadcastReceiver" android:exported="true">
<intent-filter>
<action android:name="android.net.wifi.STATE_CHANGE" />
</intent-filter>
</receiver>
But, If one wants to receive particular device state changes like Internet Connectivity Changes (Which isn't allowed) while the app is in background and if it's important for any feature of his application, what should he do?
When I was going through the documentation, My eyes got stuck here :
Context-registered receivers receive broadcasts as long as their registering context is valid. For an example, if you register within
an Activity context, you receive broadcasts as long as the activity is
not destroyed. If you register with the Application context, you
receive broadcasts as long as the app is running.
That practically means if I can hold a Context, the broadcast-receiver registered with it will run in the background.
For doing that, a Service will be the best practice.
This is below code for a STICKY_SERVICE which is started again after killed and thus the context remains valid.
AlwaysOnService.class
package app.exploitr.auto;
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.support.annotation.Nullable;
public class AlwaysOnService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
registerReceiver(new ClickReceiver(), new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE"));
return Service.START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onLowMemory() { // rem this if you want it always----
stopSelf();
super.onLowMemory();
}
}
Now, the receiver which actually does things :
ClickReceiver.class
package app.exploitr.auto;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import java.util.Objects;
public class ClickReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, Intent intent) {
switch (Objects.requireNonNull(intent.getAction())) {
case AutoJob.NOTIFICATION_CANCEL_TAG:
System.out.println("Not related");
break;
case AutoJob.LOGIN_CANCEL_TAG:
System.out.println("Not related");
break;
case "android.net.conn.CONNECTIVITY_CHANGE":
System.out.println("Oops! It works...");
break;
}
}
}
Launch Code From Any Activity Class
private void setUpBackOffWork() {
if (DataMan.getInstance(getBaseContext()).getPeriodic()) {
AutoJob.schedulePeriodic();
//Not related
}
if (DataMan.getInstance(getBaseContext()).getPureAutoLogin()) {
startService(new Intent(this, AlwaysOnService.class));
}
}
So my target was to Login into my isp automatically when I turn up my android's WiFi, and the code works smooth. It doesn't fail ever (It's running for 7 hours and 37 minutes till now and working well | not across reboots).
To keep the receiver running across reboots, try manifest registerable BOOT_COMPLETED actions. It works just like the old one.
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
Update 1
Now, as Google took one step to limit background execution & as a result you've also to make the service a foreground service. So, the procedure goes below.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, new Intent(THIS_SERVICE_CLASS_NAME.this, ACTIVITY_TO_TARGET.class), 0);
/*Handle Android O Notifs as they need channel when targeting 28th SDK*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel notificationChannel = new NotificationChannel(
"download_check_channel_id",
"Channel name",
NotificationManager.IMPORTANCE_LOW);
if (notificationManager != null) {
notificationManager.createNotificationChannel(notificationChannel);
}
builder = new Notification.Builder(this.getBaseContext(), notificationChannel.getId())
.setContentTitle("Hi! I'm service")
.setContentIntent(pendingIntent)
.setOngoing(true);
notification = builder.build();
startForeground("StackOverflow".length(), notification);
}
return START_STICKY;
}
This also applies to Xamarin Android. The Play Store demanded to upgrade my apps's SDK to 8.0 Oreo, and a bunch of stuff stopped working on it.
Microsoft's documentation on Broadcast Receivers is quite confusing:
Apps that target Android 8.0 (API level 26) or higher may not statically register for an implicit broadcast. Apps may still statically register for an explicit broadcast. There is a small list of implicit broadcasts that are exempt from this restriction.
Even Google's official docs are quite inscrutable.
On Xamarin Android it used to be enough to follow this pattern:
[BroadcastReceiver]
[IntentFilter(new string[] {MyReceiver.MyAction})]
public class MyReceiver : BroadcastReceiver
{
public const String MyAction = "com.mytest.services.MyReceiver.MyAction";
public override void OnReceive (Context context, Intent intent)
{
// ...
}
}
The IntentFilter annotation instructs the compiler to add the receiver and intent filters registrations to the Manifest file during the build process. But from target SDKs v8.0 (Oreo/API 26) and above Android ignores these configurations on Manifest (except some system implicit actions). So this means that the IntentFilter annotations only works for those exceptions, and to make your broadcast receivers receive broadcasts it is required to register them on execution time:
#if DEBUG
[Application(Debuggable=true)]
#else
[Application(Debuggable=false)]
#endif
public class MyApplication: Application
{
public override void OnCreate ()
{
base.OnCreate ();
Context.RegisterReceiver(new MyReceiver(), new IntentFilter(MyReceiver.MyAciton));
}
}
It is also possible to register a receiver only for the lifecycle of an Activity, as explained by #Toaster. You can keep sending broadcasts normally:
// ...
ApplicationContext.SendBroadcast(new Intent(MyReceiver.MyAction));
// ...
The problem
I wrote a program for Android 4.3, with a main activity, a broadcast receiver and a service. The activity binds to the service in its onCreate method. The activity has a button that schedules an alarm 10 seconds in the future. The alarm triggers the BroadcastReceiver.onReceive. This method attempts to get a hold on the binder, but there is a circumstance in which this fails and peekService returns null.
What works
Clicking the button and waiting 10 seconds
Clicking the button, clicking home, and wait in the home screen till 10 seconds are elapsed.
Clicking the button, clicking the activity list, close the activity by swiping it to the left, reopen the program and wait till 10 seconds are elapsed (you need to be fast :-).
What doesn't work
Clicking the button, clicking the activity list, close the activity by swiping it to the left and wait till 10 seconds are elapsed; this is essentially like (3.) without reopening the program.
Specifically, if I execute these 4 tests I get the following log:
02-05 20:53:29.992: D/ServiceSSCCE.MyService(476): I've been bound.
02-05 20:53:30.179: D/ServiceSSCCE.MainActivity(476): Service connected.
02-05 20:53:43.265: D/ServiceSSCCE.MyReceiver(476): Awesome, let's get this **** done!
02-05 20:53:55.460: D/ServiceSSCCE.MyReceiver(476): Awesome, let's get this **** done!
02-05 20:54:08.531: D/ServiceSSCCE.MyService(764): I've been bound.
02-05 20:54:08.663: D/ServiceSSCCE.MainActivity(764): Service connected.
02-05 20:54:10.890: D/ServiceSSCCE.MyReceiver(764): Awesome, let's get this **** done!
02-05 20:54:23.593: D/ServiceSSCCE.MyReceiver(788): I just received a null binder.
The last message shows that test (4.) failed, while previous messages show that (1.), (2.) and (3.) succedeed.
I'm aware of this, this and this answer, as well as pretty much any relevant result that Google lists in the first two pages. I tried several things, including but not limited to:
Calling startService, both from BroadcastReceiver.onReceive and from the main activity (although I'm not sure I understood how bindService and startService interact)
Fiddling with intents, in particular with context (this VS getApplicationContext and so on).
Setting the service as foreground (see this)
I'm really interested in why this happens, more than I'm interested in the solution.
MainActivity.java
package it.damix.examples.servicesscce;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
public class MainActivity extends Activity {
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d("ServiceSSCCE.MainActivity", "Service disconnected.");
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("ServiceSSCCE.MainActivity", "Service connected.");
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE);
}
public void scheduleAlarm(View view) {
AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getBroadcast(this, 101, new Intent(this, MyReceiver.class), 0);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 10000, pi);
}
}
MyReceiver.java
package it.damix.examples.servicesscce;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
IBinder binder = peekService(context, new Intent(context, MyService.class));
if (binder == null)
Log.d("ServiceSSCCE.MyReceiver", "I just received a null binder.");
else
Log.d("ServiceSSCCE.MyReceiver", "Awesome, let's get this **** done!");
}
}
MyService.java
package it.damix.examples.servicesscce;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Messenger;
import android.util.Log;
public class MyService extends Service {
static class MyHandler extends Handler {
}
#Override
public IBinder onBind(Intent arg0) {
Log.d("ServiceSSCCE.MyService", "I've been bound.");
return new Messenger(new MyHandler()).getBinder();
}
#Override
public boolean onUnbind(Intent intent) {
Log.d("ServiceSSCCE.MyService", "I've been unbound.");
return super.onUnbind(intent);
}
#Override
public void onRebind(Intent intent) {
Log.d("ServiceSSCCE.MyService", "I've been rebound.");
super.onRebind(intent);
}
}
ApplicationManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="it.damix.examples.servicesscce"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="18"
android:targetSdkVersion="18" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".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="it.damix.examples.servicesscce.MyReceiver" android:enabled="true"></receiver>
<service android:name="it.damix.examples.servicesscce.MyService" android:enabled="true"></service>
</application>
</manifest>
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="it.damix.examples.servicesscce.MainActivity" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click me to schedule an alarm..."
android:onClick="scheduleAlarm"/>
</RelativeLayout>
Links
Done that
This too
Yep
Ah-ah
Something else that doesn't help
+1 for damix911's very complete statement of the problem and steps for possible resolution. The posting of all the code allowed me to easily recreate the test app.
The short answer to the question of why case #4 fails lies in some undocumented details of peekService()'s behavior. In this post by Android framework engineer Dianne Hackborn, she explains that for peekService() to return an IBinder, some component must have previously bound to the service, causing the system to create an IBinder. That post is the only place I have found those additional conditions for obtaining an IBinder described.
Here, for cases #1 through #3, an instance of MainActivity exists and has bound to the service, creating an IBinder. When the receiver runs and calls peekService(), it obtains that IBinder. For case #4, swiping the app from the recent task list kills the entire app process: the activity and bound service. When the alarm subsequently fires, the app process is recreated for the receiver, but the activity is not launched, there is no request to bind to the service, and the service is not created, so peekService() returns null.
I was not able to reproduce damix911's solution. When I modified the service attributes to make it run as an isolatedProcess I got a security exception (KitKat device). I question how starting the service and making it a foreground service would change anything. Starting it and returning the default (super) mode does cause the service to become sticky, so that when the process is recreated after the swipe the service will be recreated. But there is still nothing binding to it, so there is no IBinder for peekService() to return.
In short
The solution involves three things:
Making the service a foreground service.
Starting it in the activity using startService and binding to it. Aparently it's not enough for peekService to having started a service; aparently someone (an activity or probably another service) must have bound to it. Why this is the case it's beyond comprehension (to me).
Adding android:isolatedService="true" in the service declaration.
In detail
MyReceiver.java is correct.
The service declared in MyService.java needs indeed to be foreground:
public class MyService extends Service {
...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification notification = new Notification.Builder(this)
.setTicker("Bla bla...")
.setContentTitle("Title...")
.setContentText("Text...")
.build();
startForeground(1234, notification);
return super.onStartCommand(intent, flags, startId);
}
...
}
This change in the service caused, at least one time, my activity to raise a connection leak warning (although I was not able to reproduce the behavior). However, it was fixed by properly unbinding the connection; this means removing the service code from onCreate and adding appropriate onResume and onStop methods to MainActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onResume() {
startService(new Intent(this, MyService.class));
bindService(new Intent(this, MyService.class), mConnection, 0);
super.onResume();
}
#Override
protected void onStop() {
unbindService(mConnection);
super.onStop();
}
We are almost done. At this point (1.), (2.) and (3.) still work, and (4.) still doesn't work. The patient, actually got worse: now BroadcastReceive.onReceive doesn't even get triggered.
The final touch that fixes everything is adding the attribute android:isolatedService="true" to the service declaration in ApplicationManifest.xml.
<service
android:name="it.damix.examples.servicesscce.MyService"
android:enabled="true"
android:isolatedProcess="true"></service>
i am trying to write a sample Android service code to test whether , the service stop itself or not after returning START_NOT_STICKY to onStartCommand. But i whenever , i closed my app , the service stop itself , whereas according to the rule START_NOT_STICKY will not allow to stop the service automatically.
MyCode :
ServiceDemo.java
package com.example.servicedemo;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent in = new Intent(this,TrackService.class);
startService(in);
}}
TrackService.java
package com.example.servicedemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class TrackService extends Service
{
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags , int startId)
{
return START_NOT_STICKY;
}
#Override
public boolean onUnbind(Intent intent)
{
return super.onUnbind(intent);
}}
this my above code , whenever i close my app , the app service stops itself , please help me out , how can i restrict my service to stop or restart itself.
close my app means , pressing home and from slide menu swipe up app to close completely
That means that you are terminating your background process. At that point, your service is gone, and since you are returning START_NOT_STICKY, it will not automatically restart.
In other words, what is happening is perfectly normal.
Close with swipe won't kill this code.
It's a service that runs in the foreground so android treats it as if it is on the screen. It runs in a seperate process so the main process can be killed. It shows a custom notification to the user when its running so its completely ligit and it is written.
Note Eclipse ADK Users only put the service in a different process when your done debugging it.
manifest
<service
android:name="com.gosylvester.bestrides.ServiceLocationRecorder"
android:process=":myService" >
</service>
</application>
MyService class
private boolean isRecording = false;
public int onStartCommand(Intent intent, int flags, int startId) {
boolean isTrackerMarker = SettingMarker.TRACKER_MARKER_DEFAULT;
if (intent != null) {
isRecording = intent.getBooleanExtra("isrecording", isRecording);
startRecording(isRecording);
}
//if isRecording keep the service running else let os know service can be killed
if (isRecording) {
startForeground(R.id.action_record, getMyCustomNotification());
return Service.START_STICKY;
} else {
stopForeground(true);
return Service.START_NOT_STICKY;
}
}
The service does get re-created, just not re-started.
If you override the onCreate and do a Log.d or a Toast, you will see that onCreate gets called after your activity and app is destroyed and even the service onDestroy is called.
So the trick to keep it running after it is re-created is to put your code on the onCreate method and use the onStartCommand just to return START_STICKY.
Note: onCreate is called before onStartCommand, so your code will run both when it is started by startService and from the system self re-creation.
Android SDK says that remote service runs in another process with the application. I thought it mean if the app stops/ is terminated..., then remote service still remains running. But it does not.
For example I have this remote service:
import java.util.Timer;
import java.util.TimerTask;
import android.app.Service;
import android.os.IBinder;
import android.util.Log;
public class WatchDogService extends Service {
private Timer timer = new Timer();
#Override
public void onCreate() {
Log.i(WatchDogService.class.getName(), "WatchDog start");
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
Log.i(WatchDogService.class.getName(), "WatchDog boo boo!!! ^^");
}
}, 0, 5000);
}
#Override
public void onDestroy() {
Log.i(WatchDogService.class.getName(), "WatchDog stop");
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(WatchDogService.class.getName(), "WatchDog has just been called...");
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
}
AndroidManifest.xml:
<service
android:name="WatchDogService"
android:process=":remote" >
<intent-filter>
<action android:name="WatchDogService" />
</intent-filter>
</service>
In another activity I call it as:
startService(new Intent("WatchDogService"));
The service starts ok. But if I go to system apps manager, then stop the app, the service is terminated too.
I want to keep the service running even if the app is terminated. How can I do that?
I want to keep the service running even if the app is terminated. How can I do that?
You don't. If the user terminates your app, your app is terminated, period. The user is in control of their Android device, not you.
Please respect the user's wishes, and try not to build apps that the user will want to force-stop, task-kill, or otherwise get rid of.
Instead of a service you may create a separate application and invoke it or
Instead of a service you may create a separate background application using AIDL described in this link:
http://developer.android.com/guide/components/aidl.html
Note that the AIDL should register a notification with an intent to start the original app when it is done and ask the user if he wishes to act on it.
I expected that "service" means service, not "application". I mean, I want something like "Service manager". But I forgot that the Applications settings in Android is for end-users, not coder.
So far, I got my answer.