Starting a service on android platform - android

I am starting a service using startService(Intent intent) method. When i call this function it reaches the onCreate of service but it is unable to call onStartCommand. Here is my code--
#Override
public void onReceive(Context context, Intent intent) {
// Send a text notification to the screen.
Log.e("mudit", "Action: " + intent.getAction());
try {
ConnectivityManager connManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = connManager.getActiveNetworkInfo();
Log.e("mudit", "getType: " + info.getType());
Log.e("mudit", "isConnected: " + info.isConnected());
if (info.isConnected()) {
Intent newinIntent = new Intent(context, service.class);
context.startService(newinIntent);
}
} catch (Exception e) {
e.printStackTrace();
Intent newinIntent = new Intent(context, service.class);
context.stopService(newinIntent);
}
}
Service Code --
package com.android.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;
public class service extends Service {
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Service created...", Toast.LENGTH_LONG).show();
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service destroyed ...", Toast.LENGTH_LONG).show();
}
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "onStartCommand...", Toast.LENGTH_LONG).show();
return 1;
}
}
Manifest.xml --
<receiver class=".AReceiver" android:name=".AReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<service class=".service" android:name=".service"
android:enabled="true" android:icon="#drawable/icon">
</service>

Unbound Service: it runs in the background indefinitely even started activity with service ends also.
Bound Service : it will run till life time of activity.
Activity can start service via startService() and it will stop via stopService().
If activity wants to interact with service, it can use bindService().
First onCreate() is called, after onStartCommand is called with the intent data provided by the activity.
Source

larsVogel solves this problem (and many others like it) in this excellent post.
this is how i adapted his code to create a connectivity receiver that monitors when the user connects to a WIFI network so as to batch upload usage data:
in the Manifest file, place a receiver and declare a service right before the end tag for your < / application >:
<receiver android:name=".ConnMonitor" android:enabled="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<service android:name=".BatchUploadGpsData" ></service>
</application>
create a broadcast receiver class in a separate file called ConnMonitor.java (please uncomment the Log calls to be able to properly monitor the flow)
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
public class ConnMonitor extends BroadcastReceiver {
private String TAG = "TGtracker";
#Override
public void onReceive(Context context, Intent intent) {
//String typeName = "";
String state = "";
int type = -1;
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE );
NetworkInfo test = (NetworkInfo) connectivityManager.getActiveNetworkInfo();
//Log.v(TAG,"there has been a CONNECTION CHANGE -> "+intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO));
try {
//typeName = test.getTypeName().toString();
type = test.getType();
state = test.getState().toString();
//Log.i(TAG,"type -> '"+typeName +"' state -> '"+state+"'" );
} catch (Exception e) {
//typeName = "null";
type = -1;
state = "DISCONNECTED";
//Log.i(TAG,"type -> error1 "+e.getMessage()+ " cause = "+e.getCause() );
}
if ( (type == 1) && (state == "CONNECTED") ) {
//Log.i(TAG, "I am soooo friggin uploadin on this beautiful WIFI connection ");
Intent batchUploadDataService = new Intent(context, BatchUploadGpsData.class);
context.startService(batchUploadDataService);
} else {
//Log.e(TAG,"NO FOUND MATCH type -> '"+typeName +"' state -> '"+state+"'" );
}
}
}
and, finally, create a service BatchUploadGpsData.java like this:
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class BatchUploadGpsData extends Service {
final String TAG = "TGtracker";
#Override
public void onCreate() {
Log.e(TAG, "here i am, rockin like a hurricane. onCreate service");
// this service tries to upload and terminates itself whether it is successful or not
// but it only effectively DOES anything while it is created
// (therefore, you can call 1 million times if uploading isnt done, nothing happens)
// if you comment this next line, you will be able to see that it executes onCreate only the first it is called
// the reason i do this is that the broadcast receiver is called at least twice every time you have a new change of connectivity state with successful connection to wifi
this.stopSelf();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Log.i(TAG, "Received start id " + startId + ": " + intent);
Log.e(TAG, "call me redundant BABY! onStartCommand service");
// this service is NOT supposed to execute anything when it is called
// because it may be called inumerous times in repetition
// all of its action is in the onCreate - so as to force it to happen ONLY once
return 1;
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
this is not pseudocode, this is actual code, tested and running on android 2.2 and up.
the way to test this service is to shut down and restart your WIFI services on your android (powering off the wifi router will also do the trick). BUT this code does not verify if you are effectively connected to the net. for that, i recomend that you make an httpclient request and check out the result of the call. beyond the scope of this discussion.
NOTE: since services run on the same thread as the UI, i highly recommend that you implement the uploading proper on a separate thread or asynctask, depending your specific needs. you can also run the whole service on a separate thread, but that is once again not the scope of this discussion, despite being standard practice in these cases.

First you should add #Override before onStartCommand(..) then make sure that the target for the Android project is higher than 2.0 .

I believe, that you cannot access any UI components like Dialog or even a Toast in a service.
try this.
public int onStartCommand(Intent intent, int flags, int startId) {
/* Toast.makeText(this, "onStartCommand...", Toast.LENGTH_LONG).show();
return 1; */
Log.i("YourService", "Yes this works.");
}

First of all name your class to something else is my recommendation to avoid confusion down the line. Second here is an example of my manifest call of a service I have that works. I use full path names when calling services and such since they are not in the same package as my application.
<service android:name="com.public.service.UploaderService" android:icon="#drawable/vgbio"></service>
Here is the gist of my service class,
package com.public.service;
....
public class UploaderService extends Service{
....
}
Third make sure you use #Override to the onStartCommand().

Related

How to run a background service in Oreo for longer period?

Android Oreo has imposed many restrictions on running background service. Services now don't behave like normal in Oreo as they used to before.
But what if I have to run a service in background for long periods of time.
I am developing an application to launch the flashlight when user shakes the phone. To achieve this I will have to put the Sensor listener code inside a service.
How do I prevent android system to not kill the service.
PS: I don't want to start a foreground service with a notification.
How do I prevent android system to not kill the service.
To summarize the comments: Use a foreground service, with a notification on a dedicated channel, with the channel set to IMPORTANCE_DEFAULT. Advise the user that they can mute that channel (e.g., long-press on the Notification in the notification shade). Using a dedicated channel means that you can still raise notifications on other channels. Your notification should also be useful:
Have a "stop" action to stop your service, if the user wants to shut it down for a while
Tapping on the notification itself would lead to your activity for configuring your app's behavior
I don't want to start a foreground service with a notification.
Then most likely you cannot write your app.
I cannot rule out the possibility of some bug in Android 8.x that could be exploited to have an indefinite-duration service. In fact, I'd consider it to be fairly likely that there's something floating around out there. However, this is clearly against Google intentions, meaning:
Exploiting that technique, without what Google would consider to be valid justification, might get your app banned from the Play Store, if that was how you planned to distribute it
The bug might be fixed in a future version of Android, and getting in an arms race with Google tends to be a losing proposition
There are enough "air gesture" apps floating about (i.e., do things based on a shake) that, ideally, Google would add some dedicated low-power API for it. For example, they could add functionality to JobScheduler to allow you to register for a shake event and have your JobService be invoked in that circumstance, just as they allow you to register for changes in a ContentProvider. I have no idea whether they will ever offer such an API, but you could file a feature request for it, if you wanted.
Make a service unstoppable on Oreo or later without shown notification is possible (Yes We Can).
Let me to explain how make a service stoppable ONLY BY USER and not by system (or better to say THE ONLY WAY TO STOP THEM IS UNINSTALLING YOUR APP).
Note that even I make a service unstoppable in my point of view is not a good technique and I’m CONTRARY on that for different reasons (like battery consuming, clear user experience etc.)
First of all you need to declare the service in manifest file.
The separate name “:serviceNonStoppable” make the service running in a separate process and not in main app process. Is better for background processes which need to run separately.
To make our own service process invisible to other processes or apps you need to set exported=false parameter.
The description “#string/service_description” will say to users what your service do and why user should not stop them (you create this description in strings.xml).
<service
android:process=":serviceNonStoppable"
android:name="your.package.name.serviceOn"
android:exported="false"
android:description="#string/service_description" />
Secondly we go to create a support class with static methods usable in different points.
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import java.util.Map;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
class Utils {
// This is a support class witch have static methods to use everywhere
final static int NOTIFICATION_INT_CHANNEL_ID = 110211; // my daughter birthday but you can change that with your number
final static String NOTIFICATION_STRING_CHANNEL_ID = "put.a.random.id.here"; //if you write "the.pen.is.on.the.table" is the same
final static int TEST_THIS = 111; // or you can put here something else
final static String BROADCAST_MSG_ID = "BROADCAST_MSG_ID"; // or you can put here something else
final static String APP_MESSAGE = "your.package.name.action.APP_MESSAGE"; // or you can put here pippo.pluto.and.papperino
static void returnUpMyService(final Context context) {
try {
//to avoid crashes when this method is called by service (from itself) make sure the service is not alredy running (maybe is in cache)
if (killServiceIfRun(context)) {
startServiceOn(context);
}
} finally {
System.out.println(" I'm trying to start service ");
}
}
private static boolean killServiceIfRun(final Context context) {
boolean isRunning = isMyServiceRunning(context);
if (!isRunning) { return true; }
try {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
// maybe killing process is not terminated by system in this fase
//I force to kill them by my one
if (manager != null) {
manager.killBackgroundProcesses(getServicename(context));
return true;
}
return true;
} catch (Exception e) {
System.out.println("killServiceIfRun error: " + e.toString());
}
return false;
}
private static boolean isServiceInCache(final Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (manager != null && manager.getRunningAppProcesses() != null) {
if (manager.getRunningAppProcesses().size() > 0) {
for (ActivityManager.RunningAppProcessInfo process : manager.getRunningAppProcesses()) {
if (process.processName != null) {
if (process.processName.equalsIgnoreCase(getServicename(context))) {
// Here we know that the service is running but sleep brrrrrrrr
if (process.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE) {
return true;
}
}
}
}
}
}
return false;
}
static void StartMyService(Context context) {
// If the sevice is running doesn't need to restart
if (isMyServiceRunning(context) && !isServiceInCache(context)) {
return;
}
// If service is running but is in chache is the same like killed, so we need to kill them
if (isServiceInCache(context)) {
// this method at first kill and after that start the service
returnUpMyService(context);
} else {
//Otherwise we start own service
startServiceOn(context);
}
}
private static void startServiceOn(final Context context) {
// After we had been sure about that service doesn't exist
// we make a schedule to restart them
new ScheduledThreadPoolExecutor(1).schedule(() -> {
//Create an instance of serviceOn
serviceOn service = new serviceOn();
//prepare the launch intent
Intent launchIntent = new Intent(context, service.getClass());
// Now we start in background our service
context.startForegroundService(launchIntent);
// I put 50 ms to allow the system to take more time to execute GC on my killed service before
}, 50, TimeUnit.MILLISECONDS);
}
private static boolean isMyServiceRunning(final Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (manager != null && manager.getRunningAppProcesses() != null) {
if (manager.getRunningAppProcesses().size() > 0) {
for (ActivityManager.RunningAppProcessInfo process : manager.getRunningAppProcesses()) {
if (process != null && process.processName != null && process.processName.equalsIgnoreCase(getServicename(context))) {
return true;
}
}
}
}
return false;
}
static void SendMsgToService(Context context, int id, Map<String, Object> params) {
try {
Intent mServiceIntent = new Intent(APP_MESSAGE);
if (params != null) {
for (Map.Entry<String, Object> entry : params.entrySet()) {
//System.out.println(entry.getKey() + "/" + entry.getValue());
if (entry.getValue() instanceof String) {
mServiceIntent.putExtra(entry.getKey(), (String) entry.getValue());
} else if (entry.getValue() instanceof Integer) {
mServiceIntent.putExtra(entry.getKey(), (Integer) entry.getValue());
} else if (entry.getValue() instanceof Float) {
mServiceIntent.putExtra(entry.getKey(), (Float) entry.getValue());
} else if (entry.getValue() instanceof Double) {
mServiceIntent.putExtra(entry.getKey(), (Double) entry.getValue());
} else if (entry.getValue() instanceof byte[]) {
mServiceIntent.putExtra(entry.getKey(), (byte[]) entry.getValue());
}
}
}
mServiceIntent.putExtra(BROADCAST_MSG_ID, id);
context.sendBroadcast(mServiceIntent);
} catch (RuntimeException e) {
System.out.println(e.toString());
}
}
private static String getServicename(final Context context) {
// the name declared in manifest you remember?
return context.getPackageName() + ":serviceNonStoppable";
}
}
This is service class witch extend IntentService.
import android.app.IntentService;
import android.app.Notification;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class serviceOn extends IntentService {
// Needed to keep up notifying without show the icon
private ScheduledExecutorService notifyer = null;
// don't remove this. cause error becouse we declare this service in manifest
public serviceOn() {
super("put.a.constant.name.here");
}
// We need this class to capture messages from main activity
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, Intent intent) {
if (intent != null) {
if (intent.getAction() != null) {
if (intent.getAction().equals(Utils.APP_MESSAGE)) {
int msgID = intent.getIntExtra(Utils.BROADCAST_MSG_ID, -1);
switch (msgID) {
case Utils.TEST_THIS:
String message = intent.getStringExtra("message");
if (!TextUtils.isEmpty(message)) {
System.out.println(message);
}
//Do your task here
//Do your task here
//Do your task here
//Do your task here
break;
}
}
}
}
}
};
#Override
protected void onHandleIntent(#Nullable Intent intent) { }
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
try {
// First of all we need to register our receiver
List<String> actions = Arrays.asList(
Utils.APP_MESSAGE, // this is the string which identify our mesages
Intent.ACTION_SCREEN_ON, // this event is raised on sreen ON by system
Intent.ACTION_SCREEN_OFF, // this event is raised on screen OFF by system
Intent.ACTION_TIME_TICK);// this event is raised every minute by system (helpful for periodic tasks)
for (String curIntFilter : actions) {
IntentFilter filter = new IntentFilter(curIntFilter);
registerReceiver(broadcastReceiver, filter);
}
} catch (RuntimeException e) {
e.printStackTrace();
}
final Notification notificationDefault = new NotificationCompat.Builder(getApplicationContext(), Utils.NOTIFICATION_STRING_CHANNEL_ID)
.setOngoing(true) //Ongoing notifications do not have an 'X' close button, and are not affected by the "Clear all" button
.setCategory(Notification.CATEGORY_SERVICE) // indicate this service is running in background
.setSmallIcon(R.drawable.ic_radio) // put here a drawable from your drawables library
.setContentTitle("My Service") // Put here a title for the notification view on the top
// A smaller explanation witch system show to user this service is running
// in background (if existing other services from other apps in background)
.setContentText("My Service is unstoppable and need to run in background ")
.build();
// This is an efficient workaround to lie the system if we don't wont to show notification icon on top of the phone but a little aggressive
notifyer = Executors.newSingleThreadScheduledExecutor();
notifyer.scheduleAtFixedRate(() -> {
try {
// Here start the notification witch system need to permit this service to run and take this on.
// And we repeat that task every 15 seconds
startForeground(Utils.NOTIFICATION_INT_CHANNEL_ID, notificationDefault);
//immediately after the system know about our service and permit this to run
//at this point we remove that notification (note that is never shown before)
stopForeground(true);
//better not invoke Exception classes on error, make all a little heavy
} finally {
// Log here to tell you your code is called
System.out.println(" Service is running");
}
// So, the first call is after 1000 millisec, and successively is called every 15 seconds for infinite
}, 1000, 15000, TimeUnit.MILLISECONDS);
}
#Override
public void onDestroy() {
// unregister the receiver
unregisterReceiver(broadcastReceiver);
// stop the notifyer
if (notifyer != null) {
notifyer.shutdownNow();
notifyer = null;
System.out.println(" notifyer.shutdownNow() ");
}
final Context context = getBaseContext();
try {
new Thread() {
#Override
public void run() {
// The magic but dirty part
// When the system detect inactivity by our service decides to put them in cache or kill it
// Yes system you can kill me but I came up stronger than before
Utils.returnUpMyService(context);
}
}.start();
} finally {
System.out.println("You stop me LOL ");
}
}
}
And here the usage.
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import java.util.HashMap;
class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Sstart the first time
Utils.StartMyService(this);
// Test after 3 seconds
new Handler().postDelayed(() -> {
Utils.SendMsgToService(X_App.getContext(), Utils.TEST_THIS, new HashMap<String, Object>() {{
put("message", "Hello from main activity");
}});
}, 3000);
}
}
I discovered that we can run forground service without showing notification for android oreo and above, here is the solution first create notification with notification Channel also set channel id for notifications then start forground service with notification. now it's time to cancel notification Channel with id after 1 or 2 second that's means the notification will remove and the service will run alwayes . that's all
You would not be able to run background services long running in Oreo as there are behaviour changes, now Oreo to optimise system memory, battery etc, it kills background service, to solve your issue you should use foreground service.
Have a look at Background execution limits
https://developer.android.com/about/versions/oreo/android-8.0-changes
Hope this helps in understanding the issue....

Android service not restarting in lollipop

In my application, I use location based service in background. So I need to restart my service when it gets destroyed.
But I got this message in logcat
Spurious death for ProcessRecord{320afaf6 20614:com.odoo.crm:my_odoo_gps_service/u0a391}, curProc for 20614: null
My service onTaskRemoved
#Override
public void onTaskRemoved(Intent rootIntent) {
System.out.println("onTaskRemoved called");
Intent restartServiceIntent = new Intent(App.getAppContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent =
PendingIntent.getService(App.getAppContext(), 1, restartServiceIntent,
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService =
(AlarmManager) App.getAppContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);
}
My service onDestroy
#Override
public void onDestroy() {
System.out.println("destroy service");
super.onDestroy();
wakeLock.release();
}
My service onStartCommand
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
I don`t know what is the error. I searched both in google & stackoverflow.
All of them refer Service.START_STICKY. but I already used it.
Same service restart works in KitKat, but with some delay(~5 mins).
Any help is appreciated.
You can restart it by using a BroadcasteReceiver which handles the broadcast sent from onDestroy() of your service.
How to do this:
StickyService.java
public class StickyService extends Service
{
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
sendBroadcast(new Intent("IWillStartAuto"));
}
#Override
public void onDestroy() {
super.onDestroy();
sendBroadcast(new Intent("IWillStartAuto"));
}
}
RestartServiceReceiver.java
public class RestartServiceReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context.getApplicationContext(), StickyService.class));
}
}
Declare the components in manifest file:
<service android:name=".StickyService" >
</service>
<receiver android:name=".RestartServiceReceiver" >
<intent-filter>
<action android:name="IWillStartAuto" >
</action>
</intent-filter>
</receiver>
Hope this will help you.
Your code in onTaskRemoved is preventing the system to run the killProcess commands. The delay on Kitkat is caused by using alarmService.set, which is inexact from API 19. Use setExact instead.
If you have a service that you want to keep alive, it is recommended that you attach a notification to it and make it foreground. That way the likeliness of it being killed would be lowered.
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Environment;
import android.os.IBinder;
import android.support.v7.app.NotificationCompat;
import java.io.File;
import java.io.IOException;
import activity.MainActivity;
import activity.R;
import fragment.MainFragment;
public class MyService extends Service {
public static final int NOTIFICATION_CODE = 1;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground(NOTIFICATION_CODE, getNotification());
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
stopForeground(true);
super.onDestroy();
}
#Override
public boolean stopService(Intent name) {
return super.stopService(name);
}
/**
* Create and return a simple notification.
*/
private Notification getNotification() {
Notification notification;
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setColor(getResources()
.getColor(R.color.material_deep_teal_500))
.setAutoCancel(true);
notification = builder.build();
notification.flags = Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTO_CANCEL;
return notification;
}
}
You can modify this code to accomodate your needs but this is the basic structure to start foreground service. Which restarts if gets killed.
how you check issocketalive that socket is connected or not ?
if sockettimeoutexception is generated then try to on set getinputstream and getoutputstream.
other issue that may be socket not closed properly.
So if possible then put your socket code here
this worked for me
Add this attribute in android:allowBackup="false" in manifest file in application tag.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="false"
tools:replace="android:allowBackup">
</application>
</manifest>
The idea of having a service ALWAYS running in background in Android is just wrong 99% of the times.
The system need to "shut down" CPU, and switch to a low battery usage profile.
You are saying you have a location based service. I assume you are using Google Play Services FusedLocationProvider, if not you should.
The FusedLocationProvider allow you to register for location changes using a PendingIntent. Meaning your services doesn't need to run all the time, it just need to register for location changes and then react when a new location come and do its stuff.
See the FusedLocationProviderApi official documentation.
To start listening for location updates
connect to the GoogleClient using the LocationServices.API API
Build your LocationRequest according to your needs (see the doc)
Call requestLocationUpdates() using the PendingIntent version
To stop listening
connect to the GoogleClient using the LocationServices.API API
Call removeLocationUpdates() using the same PendingIntent
Your PendingIntent can launch another service to handle the new location.
For example doing this from a service:
public void startMonitoringLocation(Context context) {
GoogleApiClient client = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.build()
ConnectionResult connectionResult = mApiClient.blockingConnect();
if (connectionResult.isSuccess()) {
LocationServices.FusedLocationApi
.requestLocationUpdates(client, buildLocationRequest(), buildPendingIntent(context));
} else {
handleConnectionFailed(context);
}
}
Then the service can immediately stop.
The first time this code run it WILL fail. The connection to the google client usually require the user to take some actions. The ConnectionResult.hasResolution() method will return true if this is the case. Otherwise the reason is something else and you can't recover from it. Meaning the only thing you can do is inform the user the feature will not work or have a nice fallback.
The ConnectionResult.getResolution() give you a PendingIntent you need to use an Activity and startIntentSenderForResult() method on the Activity to resolve this intent. So you would create a Notification starting your Activity to resolve that, and in the end call your Service again.
I usually just start an Activity dedicated to do all the work. It's lot easier but you don't want to call connectBlocking() in it. Check out this on how to do it.
You may ask why not requesting location updates directly in the Activity. That's actually perfectly fine, unless you need the location monitor to automatically start with the device, even if the user didn't explicitly opened the App.
<receiver android:name=".BootCompletedBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
This way you can just run your service to connect and request location updates when the device is rebooted.
Example on how you can build your location request:
public LocationRequest buildLocationRequest() {
LocationRequest locRequest = LocationRequest.create();
// Use high accuracy
locRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// how often do you need to check for the location
// (this is an indication, it's not exact)
locRequest.setInterval(REQUIRED_INTERVAL_SEC * 1000);
// if others services requires the location more often
// you can still receive those updates, if you do not want
// too many consider setting this lower limit
locRequest.setFastestInterval(FASTEST_INTERVAL_SEC * 1000);
// do you care if the user moved 1 meter? or if he move 50? 1000?
// this is, again, an indication
locRequest.setSmallestDisplacement(SMALLEST_DISPLACEMENT_METERS);
return locRequest;
}
And your pending intent:
public PendingIntent buildPendingIntent(Context context) {
Intent intent = new Intent(context, LocationUpdateHandlerService.class);
intent.setAction(ACTION_LOCATION_UPDATE);
intent.setPackage(context.getPackageName());
return PendingIntent.getService(context, REQUEST_CODE, intent, PendingIntent.FLAG_CANCEL_CURRENT);
}
Your LocationUpdateHandlerService can be an IntentService if you need to do work in background:
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
Bundle extras = intent.getExtras();
if (extras != null && extras.containsKey(FusedLocationProviderApi.KEY_LOCATION_CHANGED)) {
Location location = extras.getParcelable(FusedLocationProviderApi.KEY_LOCATION_CHANGED);
handleLocationChanged(location);
} else {
Log.w(TAG, "Didn't receive any location update in the receiver");
}
}
}
But can also be a Broadcast or anything that suits you.
Finally I achieved with help of Evernote JobService
Github link - https://github.com/evernote/android-job
Step 1: Add evernote jobservice dependency
implementation 'com.evernote:android-job:1.3.0-alpha03'
Step 2: Create DemoJobCreator.java class
public class DemoJobCreator implements JobCreator {
#Override
#Nullable
public Job create(#NonNull String tag) {
switch (tag) {
case DemoSyncJob.TAG:
return new DemoSyncJob();
default:
return null;
}
}
}
Step 3: Create DemoSyncJob.java class
public class DemoSyncJob extends Job {
public static final String TAG = ">>>> job_demo_tag";
#Override
#NonNull
protected Result onRunJob(Params params) {
// run your job here
Log.d(TAG, "onRunJob: ");
if(!isMyServiceRunning(this.getContext(), TestService.class)){
Intent intent=new Intent(context,TestService.class);
context.startService(intent);
}
scheduleJob();
return Job.Result.SUCCESS;
}
public static void scheduleJob() {
new JobRequest.Builder(DemoSyncJob.TAG)
.setExecutionWindow(2_000L, 2_000L)
//.setPeriodic(900000) -> recommended. but it will work after 15 min (if you used this no need scheduleJob(); inside onRunJob();)
.build()
.schedule();
}
public static boolean isMyServiceRunning(Context context, Class<?> serviceClass) {
try {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
}catch (Exception e){
Log.e(TAG, "isMyServiceRunning: ",e );
}
return false;
}
}
Step 4: In your Application file (If not available create it) add following line in onCreate()
JobManager.create(this).addJobCreator(new DemoJobCreator());
Step 5: Finally start JobService in your Activity
DemoSyncJob.scheduleJob();
This JobService will check service running or not (every 2 second) If service not running it will restart the service.
Disclaimer : This may be not right solution. But it will 100% working.
I hope it helps atleast anyone in future.

Restarting a service in the onDestroy method

I have made an app in which a service runs in the background. But if the android system requires resources, it will stop the service. However I may still require my service to run.
Is it a bad practice to restart the service (if condition relevant to my app still holds true) in the onDestroy method of my service?
How can I make sure my service runs indefinitely (if condition relevant to my app still holds true)? Or atleast on high priority?
Probably the best you can do is use the START_STICKY flag, which tells Android to attempt to restart the service if it has stopped. Beyond that ensure that it consumes as few resources as possible, so that it is less likely to be destroyed.
Android prioritizes the UI over everything. Then processes that are related to the UI. Then processes that are consuming the least amount of resources. A Service runs in the background, so unless it has resources that are also in use on the UI or connected to the UI in some way, it should be a lower priority.
Also you cannot tell Android how to prioritize your Service (everyone would make theirs the "highest priority" right?). So it goes by how well you minimize the impact on overall resources - why kill 3 Services when it could kill 1 and regain all the resources it needs?
To help understand how to manage memory better: http://developer.android.com/training/articles/memory.html
set it START_STICKY. It Causes after killing service the service will restart again. it is my code :
android manifest :
<application
....
<service android:name=".UpdateService" />
</application>
service class :
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class UpdateService extends Service {
BroadcastReceiver mReceiver;
#Override
public void onCreate() {
super.onCreate();
// register receiver that handles screen on and screen off logic
IntentFilter filter = new IntentFilter(Intent.....);
filter.addAction(Intent....);
mReceiver = new MyReceiver();
registerReceiver(mReceiver, filter);
}
#Override
public void onDestroy() {
unregisterReceiver(mReceiver);
Log.i("onDestroy Reciever", "Called");
super.onDestroy();
}
#Override
public void onStart(Intent intent, int startId) {
Log.i("log", "action Called");
}
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
}
receiver class :
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("Log", "recevid");
}
}
in StartupActivity :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Context context = getApplicationContext();
Intent service = new Intent(context, UpdateService.class);
context.startService(service);
}

Service stops when deploying android app (disapears from settings>>application>>RunningServices)

This is my situation: I have a service running and every time I deploy my app the service disappears from settings>>application>>runningService (therefore, the service is not running) how can I set it so that the service does not disappears?
I have tried to startForeground but it did not worked.
AndroidManifest:
<service
android:name=".service.PhoneCallInOutService"
android:enabled="true"
android:exported="false" >
</service>
This is how I start the service in my Activity:
chkCallsRecord.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
boolean isChecked = chkCallsRecord.isChecked();
updateBackgroundTasks(isChecked);
}
});
The method actually starting the service:
private void updateBackgroundTasks(boolean start) {
Intent serviceIntent = new Intent(getApplicationContext(),PhoneCallInOutService.class);
if (start) {
getApplicationContext().startService(serviceIntent);
} else {
getApplicationContext().stopService(serviceIntent);
}
}
And here is the service:
public class PhoneCallInOutService extends Service {
private TelephonyManager telephonyMgr;
private PhoneCallStateListener pcsListener;
private OutgoingCallReceiver ocReceiver;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
// Listener
pcsListener = new PhoneCallStateListener(getApplicationContext(),appDto);
telephonyMgr = (TelephonyManager)getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
telephonyMgr.listen(pcsListener, PhoneStateListener.LISTEN_CALL_STATE);
// Receiver
ocReceiver = new OutgoingCallReceiver(getApplication());
IntentFilter intentF = new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL);
getApplicationContext().registerReceiver(ocReceiver, intentF);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
// Listener
telephonyMgr.listen(pcsListener, PhoneStateListener.LISTEN_NONE);
// Receiver
getApplicationContext().unregisterReceiver(ocReceiver);
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
}
Thank you very much in advance.
If by deploy you mean you try to launch new build of your app, then this is actually normal and expected behaviour. By deploying new build you replace old code (incl. service code) therefore it have to be killed first to avoid any crashes and other oddities. So your old iteration of app is completely killed. Then new app is installed and most often auto-launched. Your data create by the app usually stay, but it's also normal.
EDIT
For security reasons you are not allowed to re-launch itself after being updated. User has to to this. As for "he/she may assume the service is still there running, which is not true", use notification of type "On Going" to indicate running service

Android Service can be bind without start?

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.

Categories

Resources