What is the best way to receive location updates in background?

前端 未结 2 1213
粉色の甜心
粉色の甜心 2021-01-25 23:42

I am trying to write an app that tracks location in background and sends data to a server -- to monitor where my family members are, for example.
Currently I am playing wi

相关标签:
2条回答
  • 2021-01-25 23:58

    It comes out for Android 5 Lollipop it's better (much more stable) to use third-party library for bacground location receiving, namely io.nlopez.smartlocation.SmartLocation from 'io.nlopez.smartlocation:library:3.3.3', as decribed here, along with a foreground service, as Rudrik Patel mentioned. Works like a charm.

    0 讨论(0)
  • 2021-01-26 00:04

    In order to get location constantly from the application, you have to use the foreground service in which you can initialize the location manager and get the location update constantly as per the parameters that have been set. Also, make sure you have background location permission given as it is the requirement after API level 29. Following is the very basic flow of how it can be achieved. Make sure to start this service after taking the location permission:

    public class MyCustomService extends Service implements
            GoogleApiClient.ConnectionCallbacks,
            GoogleApiClient.OnConnectionFailedListener {
    
        private GoogleApiClient mGoogleApiClient;
        private PowerManager.WakeLock mWakeLock;
        private LocationRequest mLocationRequest;
        private boolean mInProgress;
    
        private Boolean servicesAvailable = false;
    
        @Override
        public IBinder onBind(Intent arg0) {
            return null;
        }
    
        private static final int UPDATE_INTERVAL_IN_SECONDS = 120;
        private static final int MILLISECONDS_PER_SECOND = 1000;
        public static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS;
        private static final int FASTEST_INTERVAL_IN_SECONDS = 60;
        public static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;
    
    
        @Override
        public void onCreate() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                startForegroundService();
            }
    
            mInProgress = false;
            mLocationRequest = LocationRequest.create();
            mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
            mLocationRequest.setInterval(UPDATE_INTERVAL);
            mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
            mLocationRequest.setSmallestDisplacement(100);
            servicesAvailable = servicesConnected();
    
            /*
             * Create a new location client, using the enclosing class to
             * handle callbacks.
             */
            setUpLocationClientIfNeeded();
            super.onCreate();
    
        }
    
    
        private void setUpLocationClientIfNeeded() {
            if (mGoogleApiClient == null)
                buildGoogleApiClient();
        }
    
        /*
         * Create a new location client, using the enclosing class to
         * handle callbacks.
         */
        protected synchronized void buildGoogleApiClient() {
            this.mGoogleApiClient = new GoogleApiClient.Builder(this)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .addApi(LocationServices.API)
                    .build();
        }
    
        private boolean servicesConnected() {
    
            // Check that Google Play services is available
            int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
    
            // If Google Play services is available
            if (ConnectionResult.SUCCESS == resultCode) {
    
                return true;
            } else {
    
                return false;
            }
        }
    
        /* Used to build and start foreground service. */
        private void startForegroundService() {
            Intent notificationIntent = new Intent(this, HomeActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    
            String CHANNEL_ID = "1";
            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setSmallIcon(R.drawable.noti_icon)
                    .setPriority(Notification.PRIORITY_LOW)
                    .setOngoing(true)
                    .setAutoCancel(false)
                    .setContentTitle("ServiceTitle")
                    .setContentText("Service Reason text")
                    .setTicker("TICKER")
                    .setChannelId(CHANNEL_ID)
                    .setVibrate(new long[]{0L})
                    .setContentIntent(pendingIntent);
            Notification notification = builder.build();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "NOTIFICATION_CHANNEL_NAME", NotificationManager.IMPORTANCE_HIGH);
                channel.setDescription("NOTIFICATION_CHANNEL_DESC");
                channel.enableVibration(false);
                channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
                notificationManager.createNotificationChannel(channel);
            }
            startForeground(123, notification);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
    
            this.mInProgress = false;
    
            if (this.servicesAvailable && this.mGoogleApiClient != null) {
                this.mGoogleApiClient.unregisterConnectionCallbacks(this);
                this.mGoogleApiClient.unregisterConnectionFailedListener(this);
                this.mGoogleApiClient.disconnect();
                // Destroy the current location client
                this.mGoogleApiClient = null;
            }
    
            if (this.mWakeLock != null) {
                this.mWakeLock.release();
                this.mWakeLock = null;
            }
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            super.onStartCommand(intent, flags, startId);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                startForegroundService();
            }
            setUpLocationClientIfNeeded();
            if (!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress) {
                mInProgress = true;
                mGoogleApiClient.connect();
            }
            return START_STICKY;
    
        }
    
    
        @Override
        public void onConnected(@Nullable Bundle bundle) {
            Intent intent = new Intent(this, LocationReceiver.class);
            PendingIntent pendingIntent = PendingIntent
                    .getBroadcast(this, 54321, intent, PendingIntent.FLAG_CANCEL_CURRENT);
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            if (this.mGoogleApiClient != null)
                LocationServices.FusedLocationApi.requestLocationUpdates(this.mGoogleApiClient,
                        mLocationRequest, pendingIntent);
        }
    
        @Override
        public void onConnectionSuspended(int i) {
            // Turn off the request flag
            mInProgress = false;
            // Destroy the current location client
            mGoogleApiClient = null;
        }
    
        @Override
        public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
            mInProgress = false;
    
            /*
             * Google Play services can resolve some errors it detects.
             * If the error has a resolution, try sending an Intent to
             * start a Google Play services activity that can resolve
             * error.
             */
            if (connectionResult.hasResolution()) {
    
                // If no resolution is available, display an error dialog
            } else {
    
            }
        }
    }
    

    Here is the Location receiver class which you need to register in the Androidmanifest file also

    public class LocationReceiver extends BroadcastReceiver {
    
        private String TAG = "LOCATION RECEIVER";
    
        private LocationResult mLocationResult;
        private Context context;
        Location mLastLocation;
        
    
        @Override
        public void onReceive(Context context, Intent intent) {
            // Need to check and grab the Intent's extras like so
            this.context = context;
            if (LocationResult.hasResult(intent)) {
                this.mLocationResult = LocationResult.extractResult(intent);
                if (mLocationResult.getLocations().get(0).getAccuracy() < 100) {
    
                    // DO WHATEVER YOU WANT WITH LOCATION
                }
            }
        }
    }
    

    Permission that is required:

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

    Note: Some of the methods like FusedLocationApi and isGooglePlayServicesAvailable in above code is deprecated

    0 讨论(0)
提交回复
热议问题