Juan Juan - 1 month ago 7
Android Question

Android: Is there any Android service that can execute when the app is closed and also acts like a bound service(constant interaction)

I want to have a location updater service and I need to query it from the MainActivity. I need a service cause I need it to run on the background when the app is closed in order to send the location to a server and send notifications based on that. Also I've read that bound services act like a server and the activity like a client, and ther's no need to start the service which is ideal for the task this service has to do. Which type of service could fulfil my needs?. Thank you very much

Answer

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.

you can use a service to fired when app is closed or kill from the task:

public class App_killed extends Service {

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d("ClearFromRecentService", "Service Started");
    return START_STICKY;
}

@Override
public void onDestroy() {
    super.onDestroy();
    Log.d("ClearFromRecentService", "Service Destroyed");
}

public void onTaskRemoved(Intent rootIntent) {
    Log.e("ClearFromRecentService", "END");
    //here you can call a background network request to post you location to server when app is killed
    Toast.makeText(getApplicationContext(), "Warning: App killed", Toast.LENGTH_LONG).show();
    stopSelf(); //call this method to stop the service
}
}

delcare your service on menifest

 <service
        android:name="com.empiregroup.amarridebiker.App_killed"
        android:stopWithTask="false" />

this service will keep executing even if the app gets closed...also you can use a Binder class to get instance of the service class in any activity..

Full source code: works in my case

public class GPSTracker extends Service {

private static Context mContext;
// flag for GPS status
boolean isGPSEnabled = false;
// flag for network status
boolean isNetworkEnabled = false;
// flag for GPS status
boolean canGetLocation = false;
protected LocationManager locationManager;
static String latitude_s, longitude_s;
Thread triggerService;
private final IBinder mBinder = new MyBinder();

public GPSTracker() {
    super();
}


public GPSTracker(Context context) {
    mContext = context;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    //Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    Log.i(LOG, "Service started");
    if (intent != null) {
        addLocationListener();
     }
    return START_STICKY;
}

private void addLocationListener() {
    triggerService = new Thread(new Runnable() {
        public void run() {
            try {
                Looper.prepare();//Initialise the current thread as a looper.
                locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);

                //Criteria c = new Criteria();
                //c.setAccuracy(Criteria.ACCURACY_COARSE);

                //final String PROVIDER = locationManager.getBestProvider(c, true);

                MyLocationListener myLocationListener = new MyLocationListener();
                if (checkLocationPermission()) {
                    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000, 0, myLocationListener);
                }
                Log.d("LOC_SERVICE", "Service RUNNING!");
                Looper.loop();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }, "LocationThread");
    triggerService.start();
}

public static void updateLocation(Location location) {
    Context appCtx = Global_variable.getAppContext();

    double latitude, longitude;

    latitude = location.getLatitude();
    longitude = location.getLongitude();
    try {
        latitude_s = Double.toString(latitude);
        longitude_s = Double.toString(longitude);
    } catch (Exception e) {

    }
    Intent filterRes = new Intent();
    filterRes.setAction("mypackage.action.LOCATION");
    filterRes.putExtra("latitude", latitude);
    filterRes.putExtra("longitude", longitude);
    filterRes.putExtra("id", id);
    appCtx.sendBroadcast(filterRes);
}


class MyLocationListener implements LocationListener {

    @Override
    public void onLocationChanged(Location location) {
        updateLocation(location);
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }
}


public boolean checkLocationPermission() {
    String permission = "android.permission.ACCESS_FINE_LOCATION";
    int res = mContext.checkCallingOrSelfPermission(permission);
    return (res == PackageManager.PERMISSION_GRANTED);
}


@Override
public void onCreate() {
    super.onCreate();
    Log.d(LOG, "Service created");
}


@Override
public void onDestroy() {
    super.onDestroy();
    Log.d(LOG, "Service destroyed");
}


/**
 * Function to check GPS/wifi enabled
 *
 * @return boolean
 */
public boolean canGetLocation() {
    locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
    // getting GPS status
    isGPSEnabled = locationManager
            .isProviderEnabled(LocationManager.GPS_PROVIDER);

    // getting network status
    isNetworkEnabled = locationManager
            .isProviderEnabled(LocationManager.NETWORK_PROVIDER);

    if (!isGPSEnabled && !isNetworkEnabled) {
        // location service disabled
        canGetLocation = false;
    } else {
        canGetLocation = true;
    }
    return canGetLocation;
}

/**
 * Function to show settings alert dialog
 * On pressing Settings button will lauch Settings Options
 */
public void showSettingsAlert() {
    AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
    // Setting Dialog Title
    alertDialog.setTitle("GPS is settings");
    // Setting Dialog Message
    alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?");
    // On pressing Settings button
    alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            mContext.startActivity(intent);
        }
    });

    // on pressing cancel button
    alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            dialog.cancel();
        }
    });

    // Showing Alert Message
    alertDialog.show();
}

@Override
public IBinder onBind(Intent arg0) {
    return mBinder;
}

public class MyBinder extends Binder {
    GPSTracker getService() {
        return GPSTracker.this;
    }
}

public String getLatitude_s() {
    return latitude_s;
}

public String getLongitude_s() {
    return longitude_s;
}

}

The broadcast receiver class for getting location from service and send it to server.

public class LocationReceiver extends BroadcastReceiver {

double latitude, longitude;

@Override
public void onReceive(final Context context, final Intent calledIntent)
{
    Log.d("LOC_RECEIVER", "Location RECEIVED!");

    latitude = calledIntent.getDoubleExtra("latitude", -1);
    longitude = calledIntent.getDoubleExtra("longitude", -1);

    updateRemote(latitude, longitude,biker_id);

}

private void updateRemote(final double latitude, final double longitude ,final String id)
{
    //HERE YOU CAN PUT YOUR ASYNCTASK TO UPDATE THE LOCATION ON YOUR SERVER
    String latitude_s=Double.toString(latitude);
    String longitude_s=Double.toString(longitude);
    new SendToServer().execute(longitude_s, latitude_s,id);
}

in Manifest file add the services and receiver

    <service
        android:name="com.yourpackage.GPSTracker"
        android:enabled="true"
        android:label="GPS Data"></service>

    <service
        android:name="com.yourpackage.App_killed"
        android:stopWithTask="false" />

    <receiver
        android:name="com.yourpackage.LocationReceiver"
        android:enabled="true">
        <intent-filter>
            <action android:name="mypackage.action.LOCATION" />
        </intent-filter>
    </receiver>

start the service in an activity:

  GPSTracker gps;
  gps = new GPSTracker(this);
        // check if GPS enabled
        if (gps.canGetLocation()) {
            startService(new Intent(getApplicationContext(), GPSTracker.class));
            } else {
            gps.showSettingsAlert();
        }