Search code examples
androidgoogle-mapsbackground-processandroid-mapsandroid-wake-lock

How to make an android app run in background when the screen sleeps?


I am developing a Tracking app, which keeps tracks of the user by getting his current location for every 3 secs. I am able to fetch the lat long values when the screen is on. but when the screen sleeps. i am unable to fetch the datas.

CODE:

@Override
public void onLocationChanged(Location location) {
    mLastLocation = location;
    if (mCurrLocationMarker != null)
    {
        mCurrLocationMarker.remove();
    }
    latitude = location.getLatitude();
    longitude = location.getLongitude();
    latLngcurrent = new LatLng(location.getLatitude(), location.getLongitude());

    Toast.makeText(context,String.valueOf(latitude)+" "+String.valueOf(longitude), Toast.LENGTH_LONG).show();

    Log.d("onLocationChanged", String.format("latitude:%.3f longitude:%.3f",latitude,longitude));


    Log.d("onLocationChanged", "Exit");
    Toast.makeText(this, "exiting LocationChanged ", Toast.LENGTH_SHORT).show();
    }

The above given onLocationChanged method fetches the lat lon values for every 3 seconds. What should i do to make this method run even if the screen sleeps. I have read about Wakelock dont know how to implement it, any help will be appreciated. Thanks in advance.

Note: The app runs perfectly when multi tasking is done,


Solution

  • You need to make use of Service to get location updates even if screen sleep or your app is not open.

    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.location.Location;
    import android.location.LocationManager;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.util.Log;
    
    public class MyLocationService extends Service
    {
        private static final String TAG = "MyLocationService";
        private LocationManager mLocationManager = null;
        private static final int LOCATION_INTERVAL = 3000;
        private static final float LOCATION_DISTANCE = 10f;
    
        LocationListener[] mLocationListeners = new LocationListener[] {
                new LocationListener(LocationManager.GPS_PROVIDER),
                new LocationListener(LocationManager.NETWORK_PROVIDER)
        };
    
        @Override
        public IBinder onBind(Intent arg0)
        {
            return null;
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId)
        {
            Log.e(TAG, "onStartCommand");
            super.onStartCommand(intent, flags, startId);
            return START_STICKY;
        }
    
        @Override
        public void onCreate()
        {
            Log.e(TAG, "onCreate");
            initializeLocationManager();
            try {
                mLocationManager.requestLocationUpdates(
                        LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
                        mLocationListeners[1]);
            } catch (java.lang.SecurityException ex) {
                Log.i(TAG, "fail to request location update, ignore", ex);
            } catch (IllegalArgumentException ex) {
                Log.d(TAG, "network provider does not exist, " + ex.getMessage());
            }
            try {
                mLocationManager.requestLocationUpdates(
                        LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
                        mLocationListeners[0]);
            } catch (java.lang.SecurityException ex) {
                Log.i(TAG, "fail to request location update, ignore", ex);
            } catch (IllegalArgumentException ex) {
                Log.d(TAG, "gps provider does not exist " + ex.getMessage());
            }
        }
    
        @Override
        public void onDestroy()
        {
            Log.e(TAG, "onDestroy");
            super.onDestroy();
            if (mLocationManager != null) {
                for (int i = 0; i < mLocationListeners.length; i++) {
                    try {
                        mLocationManager.removeUpdates(mLocationListeners[i]);
                    } catch (Exception ex) {
                        Log.i(TAG, "fail to remove location listners, ignore", ex);
                    }
                }
            }
        }
    
        private void initializeLocationManager() {
            Log.e(TAG, "initializeLocationManager");
            if (mLocationManager == null) {
                mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
            }
        }
    
        // create LocationListener class to get location updates
        private class LocationListener implements android.location.LocationListener
        {
            Location mLastLocation;
    
            public LocationListener(String provider)
            {
                Log.e(TAG, "LocationListener " + provider);
                mLastLocation = new Location(provider);
            }
    
            @Override
            public void onLocationChanged(Location location)
            {
                Log.e(TAG, "onLocationChanged: " + location);
                mLastLocation.set(location);
            }
    
            @Override
            public void onProviderDisabled(String provider)
            {
                Log.e(TAG, "onProviderDisabled: " + provider);
            }
    
            @Override
            public void onProviderEnabled(String provider)
            {
                Log.e(TAG, "onProviderEnabled: " + provider);
            }
    
            @Override
            public void onStatusChanged(String provider, int status, Bundle extras)
            {
                Log.e(TAG, "onStatusChanged: " + provider);
            }
        }
    }
    

    Add MyLocationService into your AndroidManifest.xml also:

    <service android:name=".MyLocationService" android:process=":mylocation_service" />
    

    Don't forgot to add below two permissions in your AndroidManifest.xml file:

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    

    Start Service from an activity:

    You can start a service from an activity or other application component by passing an Intent (specifying the service to start) to startService(). The Android system calls the service's onStartCommand() method and passes it the Intent.

    Intent intent = new Intent(this, MyLocationService.class);
    startService(intent);
    

    Update:

    You need to hold partial wake lock to run service even after device screen off.

    If you hold a partial wake lock, the CPU will continue to run, regardless of any display timeouts or the state of the screen and even after the user presses the power button.

    To acquire wake lock:

    PowerManager mgr = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
    WakeLock wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
    wakeLock.acquire();
    

    To release it:

    wakeLock.release();