Фоновое обновление местоположения в Android периодически

Я использую API-интерфейс Google Chrome для определения местоположения каждые 5 минут. Это обновление как в фоновом режиме, а также, когда приложение убито. Но оно перестает обновляться через 2-3 дня. Я проверил в большинстве устройств Android.

Я звоню в эту Службу из Активности и убиваю приложение, оно отправляет обновления местоположения каждые 5 минут в течение почти 3 дней, после чего оно останавливается. Я пытался так много раз.

Открытый класс GPSTracker расширяет Сервис реализует GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location.LocationListener {защищенная статическая конечная строка String TAG = "Location..."; закрытый контекст mContext = this;

/**
 * Tracks the status of the location updates request.
 */
public static Boolean mRequestingLocationUpdates;
/**
 * Time when the location was updated represented as a String.
 */
protected String mLastUpdateTime;
/**
 * Provides the entry point to Google Play services.
 */
protected GoogleApiClient mGoogleApiClient;
/**
 * Stores parameters for requests to the FusedLocationProviderApi.
 */
protected LocationRequest mLocationRequest;

/**
 * Represents a geographical location.
 */
protected Location mCurrentLocation;
public static boolean isEnded = false;


@Override
public void onCreate() {
    super.onCreate();

    buildGoogleApiClient();
}

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


@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    Log.d("LOC", "Service init...");
    isEnded = false;
    mRequestingLocationUpdates = false;
    mLastUpdateTime = "";
    // buildGoogleApiClient();
    if (mGoogleApiClient.isConnected() && mRequestingLocationUpdates) {
        startLocationUpdates();
    }
    return START_STICKY;
}




@Override
public void onConnected(Bundle bundle) {

    startLocationUpdates();
}

@Override
public void onConnectionSuspended(int i) {
    // The connection to Google Play services was lost for some reason. We call connect() to
    // attempt to re-establish the connection.
    Log.i(TAG, "Connection suspended==");
    mGoogleApiClient.connect();
}

@Override
public void onLocationChanged(Location location) {
    mCurrentLocation = location;
    mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
    double latitude = location.getLatitude();
    double longitude = location.getLongitude();

    StringBuilder stringBuilder = new StringBuilder();
    StringBuilder latlong = stringBuilder.append(latitude + "," + longitude);

    Calendar cal = Calendar.getInstance();
    String zone = TimeZone.getDefault().getDisplayName(false, android.icu.util.TimeZone.SHORT);
    SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM 'at' h:mm a");
    Date date = new Date();
    String localtime = (formatter.format(date)).toString();

    Date myDate = new Date();

    Calendar calendar = Calendar.getInstance();
    calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
    calendar.setTime(myDate);
    date = calendar.getTime();
    SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss zz");
    dateFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
    String utc = dateFormatter.format(date);

  //  DateFormat df = DateFormat.getTimeInstance();
  //  df.setTimeZone(TimeZone.getTimeZone("gmt"));
  //  String gmtTime = df.format(new Date());

    String model = Build.MODEL;

    String reqString = Build.VERSION.RELEASE
            + " " + Build.VERSION_CODES.class.getFields()[android.os.Build.VERSION.SDK_INT].getName();

    // Date currentTime = Calendar.getInstance().getTime();
    // String localtime = currentTime.toString();

    PreferencesClass preferencesClass = new PreferencesClass(mContext);
    String id = preferencesClass.getFingerPrint();

    Data data = null;
    try {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userId", id);
        jsonObject.put("latLon", latlong);
        jsonObject.put("timeZone", zone);
        jsonObject.put("localTime", localtime);
        jsonObject.put("osVersion",reqString);
        jsonObject.put("phoneModel",model);
        jsonObject.put("utcTime",utc);
        data = new Data();
        data.setData(jsonObject.toString());

        if (data != null) {

            if (Utility.isConnectingToInternet(mContext)) {

               // boolean isChecked = preferencesClass.getIsChecked();
              //  if (isChecked){

                    LocationWebServiceMgr locationWebServiceMgr = new LocationWebServiceMgr();
                    locationWebServiceMgr.Location(data, new CallBackInterface() {
                        @Override
                        public void onResponse(ArrayList<Object> objects, ResponseMetaData responseMetaData) {

                            Log.d(TAG, "onResponse: Succesfully added the location to server");
                            // Toast.makeText(getApplicationContext(), "added to server", Toast.LENGTH_LONG).show();
                        }

                        @Override
                        public void onFailure(ResponseMetaData t) {
                        }
                    });

               // } else {
                 //   Log.d("serverCall", "Location Permission not available ");

              //  }

            } else {

                Log.e("serverCall", "Network not available");

            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
    // Refer to the javadoc for ConnectionResult to see what error codes might be returned in
    // onConnectionFailed.
    Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + connectionResult.getErrorCode());
}

/**
 * Builds a GoogleApiClient. Uses the {@code #addApi} method to request the
 * LocationServices API.
 */
protected synchronized void buildGoogleApiClient() {
    Log.i(TAG, "Building GoogleApiClient===");
    mGoogleApiClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();

    createLocationRequest();
}

/**
 * Sets up the location request. Android has two location request settings:
 * {@code ACCESS_COARSE_LOCATION} and {@code ACCESS_FINE_LOCATION}. These settings control
 * the accuracy of the current location. This sample uses ACCESS_FINE_LOCATION, as defined in
 * the AndroidManifest.xml.
 * <p/>
 * When the ACCESS_FINE_LOCATION setting is specified, combined with a fast update
 * interval (5 seconds), the Fused Location Provider API returns location updates that are
 * accurate to within a few feet.
 * <p/>
 * These settings are appropriate for mapping applications that show real-time location
 * updates.
 */
protected void createLocationRequest() {
    mGoogleApiClient.connect();
    mLocationRequest = new LocationRequest();

    // Sets the desired interval for active location updates. This interval is
    // inexact. You may not receive updates at all if no location sources are available, or
    // you may receive them slower than requested. You may also receive updates faster than
    // requested if other applications are requesting location at a faster interval.
    mLocationRequest.setInterval(Constants.UPDATE_INTERVAL_IN_MILLISECONDS);

    // Sets the fastest rate for active location updates. This interval is exact, and your
    // application will never receive updates faster than this value.
    mLocationRequest.setFastestInterval(Constants.FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);

   // mLocationRequest.setSmallestDisplacement(Constants.DISPLACEMENT);

    //mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}

/**
 * Requests location updates from the FusedLocationApi.
 */
protected void startLocationUpdates() {
    if (!mRequestingLocationUpdates) {
        mRequestingLocationUpdates = true;

        // The final argument to {@code requestLocationUpdates()} is a LocationListener
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        LocationServices.FusedLocationApi.requestLocationUpdates(
                mGoogleApiClient, mLocationRequest, this);
        Log.i(TAG, " startLocationUpdates===");
        isEnded = true;
    }
}

}

3 ответа

Используйте workmanager, чтобы перенести службу определения местоположения. Проверьте, не запущена ли служба определения местоположения, а затем запустите из планировщика. Чтобы узнать больше о Workmanager, нажмите здесь

Вы можете создать сервис для этого

public class TimeService extends Service {
    // constant
    public static final long NOTIFY_INTERVAL = 10 * 1000; // 10 seconds

    // run on another Thread to avoid crash
    private Handler mHandler = new Handler();
    // timer handling
    private Timer mTimer = null;

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

    @Override
    public void onCreate() {
        // cancel if already existed
        if(mTimer != null) {
            mTimer.cancel();
        } else {
            // recreate new
            mTimer = new Timer();
        }
        // schedule task
        mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0, NOTIFY_INTERVAL);
    }

    class TimeDisplayTimerTask extends TimerTask {

        @Override
        public void run() {
            // run on another thread
            mHandler.post(new Runnable() {

                @Override
                public void run() {
                    // display toast
                   startService(new Intent(this, MyService.class));
                }

            });
        }

        private String getDateTime() {
            // get date time in custom format
            SimpleDateFormat sdf = new SimpleDateFormat("[yyyy/MM/dd - HH:mm:ss]");
            return sdf.format(new Date());
        }

    }

и сервис для размещения

public class MyService extends Service
{
    private static final String TAG = "BOOMBOOMTESTGPS";
    private LocationManager mLocationManager = null;
    private static final int LOCATION_INTERVAL = 1000;
    private static final float LOCATION_DISTANCE = 10f;

    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);
        }
    }

    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);
        }
    }
}

Создать класс для локации get.

 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);
    }
}

в методе изменения onLocation(Location location) вы получите текущий let,long

Для этого вы можете использовать AlarmManager или firebase jobdispatcher или планировщик заданий для запуска любого события через определенные промежутки времени. Я предлагаю вам использовать AlarmManager, который является самым простым.

Используйте этот код для установки будильника:

  Calendar calendar = Calendar.getInstance();
  calendar.setTimeInMillis(System.currentTimeMillis());
  int notificationID = 2018;

 AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
 Intent intent = new Intent(this, AlarmReceiver.class);
 PendingIntent pendingIntent = PendingIntent.getBroadcast(this, notificationID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
 alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),5*1000, pendingIntent);

И вы можете отменить сигнал тревоги следующим образом:

    AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(this, AlarmReceiver.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(this, notificationID, intent, PendingIntent.FLAG_CANCEL_CURRENT);
    alarmManager.cancel(pendingIntent);
    pendingIntent.cancel();

Примечание. Начиная с API 19 (KITKAT), выдача аварийных сигналов является неточной: ОС будет сдвигать аварийные сигналы, чтобы минимизировать пробуждения и использование батареи. Существуют новые API для поддержки приложений, которые требуют строгих гарантий доставки; см. setWindow(int, long, long, PendingIntent) и setExact(int, long, PendingIntent). Приложения, для которых targetSdkVersion более ранний, чем API 19, будут по-прежнему видеть предыдущее поведение, при котором все тревоги доставляются точно по запросу.

Другие вопросы по тегам