I have an application with a Service registered in the AndroidManifest to start up at boot time. I do this via an Intent Receiver for BOOT_COMPLETED, and this works fine. However, if the user is starting the app right after installation, I'd like to start off the Service from my main Activity since it may not be running.
I'm not sure of the best way to do this. I know I can call startService() from the activity, and that works, but then I can have multiple instances of the service running. I don't want to stop the service first, becusae if it's running, I just want that instance to keep running. The service could be in the middle of a task and I don't want it to stop.
In Activity:
Intent serviceIntent = new Intent();
serviceIntent.setAction(MessageReceiverService.ClassName);
startService(serviceIntent);
Android Manifest registeing intent:
<receiver android:name="com.app.proto1.service.StartupIntentReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>
My Service overload methods:
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
Log.d(Tag, "onCreate()");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(Tag, "onDestroy()");
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Log.d(Tag, "onStart()");
this.registerReceiver(new SmsReceiver(), new IntentFilter(SMS_ACTION));
}
Is there a way I can check if the service is already running and not start it again, and without destroying the existing one?
Well if your Service is already running and you try to start service again, there will be no new instance created for the Service it will consider the previous running instance only. So, there is nothing to worry in that case. If you call the Service while its running its onStartCommand(Intent, int, int) will be called and not onCreate().
Related
I have the following service declared in the manifest:
<application
...
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.example.android.test.TestService"
android:process=":Remote"
android:permission="android.permission.WAKE_LOCK"/>
<receiver android:name="com.example.android.test.TestService">
<intent-filter>
<action android:name="android.intent.action.BATTERY_CHANGED"/>
</intent-filter>
</receiver>
</application>
and this is the Service class
public class TestService extends Service implements SensorEventListener {
public class BatteryReceiver_andFileChecker extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//TODO
}
// constructor
public BatteryReceiver_andFileChecker(){
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
//TODO
return START_STICKY;
}
#SuppressLint("WakelockTimeout")
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Logging service started new", Toast.LENGTH_SHORT).show();
//Acquire wake lock
PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
this.wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WLTAG:MyWakelockTag");
wakeLock.acquire();
//Display notification
this.notIntent = new Intent(this, MainActivity.class);
this.pendingIntent = PendingIntent.getActivity(this, 0, this.notIntent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, this.channelID).setSmallIcon(R.drawable.ic_launcher_background).setContentTitle("Test").setContentText("Sensor is recording").setPriority(NotificationCompat.PRIORITY_DEFAULT).setContentIntent(this.pendingIntent);
startForeground(this.NOTIFICATION, builder.build());
//BatteryCheck
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
mReceiver = new BatteryReceiver_andFileChecker();
registerReceiver(mReceiver, filter);
}
#Override
public void onDestroy() {
super.onDestroy();
//cancel notification
stopForeground(true);
//Unregister battery receiver
unregisterReceiver(mReceiver);
//release wakeLock
wakeLock.release();
//Stop Service
stopSelf();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
// super.onBind(intent);
return null;
}
#Override
public void onSensorChanged(SensorEvent event) {
//TODO
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
And this services is created and terminated on two different "onclick" functions from the MainActivity
public class MainActivity extends AppCompatActivity {
...
public void onClickStart(View v) {
// Start Service
this.intent = new Intent(getApplicationContext(), TestService.class);
this.intent.putExtra("foo",foo);
startService(this.intent);
}
public void onClickStopAcquisition(View v) {
// Stop Service
stopService(this.intent);
}
}
This code runs as expecten in Android 6.0.1 and does not work on Android 10...
When I debug de app, no errors are fired when pressed the Start and Stop buttons in both OS, nevertheless, android 6.0.1 fires the service and android 10 does not...
Any reason why?
Just to keep in mind when understanding my implementation, my intention is to make a service which keeps running and doing stuff even if the user is not active in the application. Since I implementen the SensorEventListener to record data from sensors, my intention is to record data while the user might be interacting with the phone or even doing nothing (after he presses the power button of the phone, the service keeps running acquiring data and performing actions)
Then, the service should be terminated either when the user clicks the stop button or either when the MainActivity is terminated.
Thank you!
i guess you should read more about background services and broadcast in android API 26 or higher
From the official documentation available here
If an app registers to receive broadcasts, the app's receiver consumes resources every time the broadcast is sent. This can cause problems if too many apps register to receive broadcasts based on system events; a system event that triggers a broadcast can cause all of those apps to consume resources in rapid succession, impairing the user experience. To mitigate this problem, Android 7.0 (API level 24) placed limitations on broadcasts, as described in Background Optimization. Android 8.0 (API level 26) makes these limitations more stringent.
Apps that target Android 8.0 or higher can no longer register
broadcast receivers for implicit broadcasts in their manifest. An
implicit broadcast is a broadcast that does not target that app
specifically. For example, ACTION_PACKAGE_REPLACED is an implicit
broadcast, since it is sent to all registered listeners, letting them
know that some package on the device was replaced. However,
ACTION_MY_PACKAGE_REPLACED is not an implicit broadcast, since it is
sent only to the app whose package was replaced, no matter how many
other apps have registered listeners for that broadcast. Apps can
continue to register for explicit broadcasts in their manifests. Apps
can use Context.registerReceiver() at runtime to register a receiver
for any broadcast, whether implicit or explicit.
Broadcasts that require a signature permission are exempted from this restriction, since these broadcasts are only sent to apps that are signed with the same certificate, not to all the apps on the device
you should work with JobScheduler
Important Update
to answer your question in comment : use WorkManager for deferrable background tasks.
This library is backward compatible
It use JobScheduler,FirebaseJobDispatcher or AlarmManager
No Need to depend on play service library.
Recommended by Google for deferrable background work.
Can use features like chaining, constraints etc.
I need to do a logout after some time, so I'm opening the login window in my app using.
startActivity(intent);
Problem is that, if the user has my app in the background, my activity will pop up.
Is there a way to easily open an activity but keep my app in the background?
It can be done with Android appliaction component Service.
you can read about it in official documentation by links below.
https://developer.android.com/training/run-background-service/create-service#java
https://developer.android.com/guide/components/services?hl=en
Initialize your Service
public class MyBackgroundService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
//onCreate - Service created
}
#Override
public void onDestroy() {
//onDestroy - Service destroyed (Stopped)
}
#Override
public void onStart(Intent intent, int startid) {
//onStart - Service started
}
}
Then call Service in your Main Activity
startService(new Intent(this, MyBackgroundService.class));
And don't forget about declare in Manifest.
<service android:enabled="true"
android:name=".MyBackgroundService" />
You can implement "local logout" after some time and when user returns to activity you can detect it. More: https://developer.android.com/guide/components/activities/activity-lifecycle
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"/>
In many articles, tutorials, docs, have read so far, that we call startService() or bindService(), both starts the service. We can call both also, but that's a different story. I am unable to bindService without startService().
private void bindTunManagerService(int flags) {
TunnelManagerService.setParentActivity(this);
Intent bindIntent = new Intent(this, TunnelManagerService.class);
startService(bindIntent);
tunManagerServiceStarted = bindService(bindIntent, tunConnection, BIND_AUTO_CREATE);
Log.d(TAG, "tunManagerServiceStarted : " + tunManagerServiceStarted + ", ** tunManagerService = " + tunManagerService );
In the above code, if I comment startService(), bindService returns false and tunManagerService = null, even onServiceConnected is not fired up and I get "Unable to sart service intent {...} not found" message. After adding startService, service's onCreate, onStart, onServiceConnected are called and is successfully bounded.
In practical usage, is it necesary to first startServie & then only we can bindService(). It implies that without startSErvice, we can't bindService !! If this statement is wrong, why I can't bindService without starting it ?
Any ideas ????
CODE ADDED
ServiceConnection :
private ServiceConnection tunConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(TAG,"onServiceConnected" );
tunManagerService = ITunnelManagerService.Stub.asInterface(service);
doConnect();
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG,"onServiceDisconnected" );
tunManagerService = null;
}
};
Service :
public class TunnelManagerService extends Service {
#Override
public IBinder onBind(Intent arg0) {
return binder;
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "TunnelManagerService: onCreate");
setCreatedPreference(true);
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Received start id " + startId + ": " + intent);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
setCreatedPreference(false);
hideNotifConnected();
Log.d(TAG, "TunnelManagerService: onDestroy");
}
private final ITunnelManagerService.Stub binder = new ITunnelManagerService.Stub() {
// contains all methods
}
...............
.............
}
Manifest :
<activity android:name=".StartUltimate" android:label="#string/app_name"
android:launchMode="singleTask" android:windowSoftInputMode="stateHidden|adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="orange.android.vpn.utilities.TunnelManagerService" android:enabled="true"></service>
I use 2.3.3 SDK i.e. API 10. My activity from which I am calling is in "orange.android.vpn" and the service related files are in "orange.android.vpn.utilities" packages respectively.
I found the solution, so am sharing with all of you.
There are 2 types of Services : One where you start and stop. This can be started and stopped only once in an application.
Other you Bind and Unbind as required N number of times.
My Service is of second type. But just bind and unbind doesn't do the job. The service first needs to be started then only it cna be bound and unbound. So on start of app or whereever appropriate, Start the service. Then Bind when required. When don with it, Unbind it. That Bind-Unbind circle can go on. And Finally when you are sure you don't need it or at the end of the app Stop the Service. So the flow comes as
Start -> Bind -> Unbind -> Stop
<-
Hope this helps someone.
Yes.
bindService(new Intent(this, MyService.class), mConnection, 0);
AFAIK, this will always return true (assuming there is no problem with MyService)
There are two scenarios:
The service has previously been started - mConnection's onServiceConnected() is called
The service has NOT previously been started - mConnection's onServiceConnected() is NOT called and the service is NOT started. However, as soon as the service is started (by some other means), the onServiceConnected() is then called
In practice, when I call this method, I assume the service is not started until the onServiceConnected() method is called.
In my app, I have an Activity from which I want to start a Service. Can anybody help me?
Add this in your code
Intent serviceIntent = new Intent(this, ServiceName.class);
startService(serviceIntent);
Dont forget to add service tag in AndroidManifest.xml file
<service android:name="com.example.ServiceName"></service>
From the Android official documentation:
Caution: A service runs in the same process as the application in
which it is declared and in the main thread of that application, by
default. So, if your service performs intensive or blocking operations
while the user interacts with an activity from the same application,
the service will slow down activity performance. To avoid impacting
application performance, you should start a new thread inside the
service.
The application can start the service with the help of the Context.startService method. The method will call the onCreate method of the service if service is not already created; else onStart method will be called. Here is the code:
Intent serviceIntent = new Intent();
serviceIntent.setAction("com.testApp.service.MY_SERVICE");
startService(serviceIntent);
First create service from android Manifest.xml file (i.e from application tab) and give some name to it.
On the activity on some event like click or touch to include the code from the service:
public void onClick(View v)
{
startService(new Intent(getApplicationContext(),Servicename.class));
}
If you want to stop the running or started service then include this code:
public void onclick(View v)
{
stopService(new Intent(getApplicationContext,Servicename.class));
}
The API Demos have some examples that launch services.
Use a Context.startService() method.
And read this.
in kotlin you can start service from activity as follow :
startService!!.setOnClickListener { startService() }
private fun startService(){
startService(Intent(this, HitroService::class.java))
}
If you want to start a service and it should run in background use START_STICKY in your corresponding service.
You can start service with on boot also,
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
And create receiver,
<receiver android:name=".auth.NotificationBroadcast" android:enabled="true" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
In Brodcast Receiver add,
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("BroadcastReceiverBroadcast--------------------ReceiverBroadcastReceiverBroadcastReceiver----------------BroadcastReceiver");
if (intent != null) {
String action = intent.getAction();
switch (action) {
case Intent.ACTION_BOOT_COMPLETED:
System.out.println("Called on REBOOT");
// start a new service
startService(new Intent(getApplicationContext(),Servicename.class));
break;
default:
break;
}
}
}
And your service is like,