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

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

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

public class GPSTracker extends Service implements
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener,
        com.google.android.gms.location.LocationListener {

    protected static final String TAG = "Location...";
    private Context 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;
        }
    }
}

person Nethra    schedule 04.04.2018    source источник
comment
Измените вопрос, чтобы добавить код, в котором местоположение обновляется в фоновом режиме, чтобы предоставить больше контекста.   -  person Darshan Pania    schedule 04.04.2018


Ответы (4)


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

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);
        }
    }
}
person Ahmad Nemati    schedule 04.04.2018
comment
Я вызываю эту службу времени из Activity, она обновляется, когда приложение находится в фоновом режиме. Но это не обновление, когда приложение убито. - person Nethra; 04.04.2018
comment
запустить службу в классе приложения - person Ahmad Nemati; 04.04.2018
comment
Элемент управления поступает в метод MyService OnStart каждые 5 минут, но элемент управления не поступает в метод OnLocatioChanged - person Nethra; 05.04.2018
comment
вы можете легко поместить таймер в класс MyService для прослушивателя управления - person Ahmad Nemati; 05.04.2018
comment
Мне очень жаль, что я не могу это решить. Я новичок в Android. Не могли бы вы помочь мне в решении этой проблемы. - person Nethra; 05.04.2018
comment
см. эту ссылку examples.javacodegeeks.com/android/core/ os / handler / - person Ahmad Nemati; 05.04.2018

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

person Sadashiv    schedule 24.12.2019

Создайте класс для местоположения 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

person Nitin Sharma    schedule 04.04.2018

Для этого вы можете использовать AlarmManager или < a href = "https://github.com/firebase/firebase-jobdispatcher-android" rel = "nofollow noreferrer"> 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, продолжат видеть предыдущее поведение, при котором все алармы доставляются точно по запросу.

person immodi    schedule 04.04.2018
comment
Я пробовал вызвать диспетчер сигналов тревоги из активности, но он не звонит, когда приложение убито. Если мне нужно вызвать диспетчер сигналов тревоги из службы, какой метод мне следует вызвать. - person Nethra; 04.04.2018
comment
@TimCastelijns, Google до сих пор не отказался от AlarmManager. Мы можем использовать его для запуска события с определенными интервалами ... пожалуйста, обратитесь к этому и когда Google удалит этот метод, никто не будет его использовать. - person immodi; 04.04.2018
comment
@TimCastelijns, есть ли какой-либо другой способ вызвать какое-либо событие в определенное время в фоновом режиме? - person immodi; 04.04.2018
comment
перестань пинговать меня - person Tim; 04.04.2018
comment
@TimCastelijns, я не пингую вас, но вы должны дать правильный ответ на этот вопрос. - person immodi; 04.04.2018
comment
вы пингуете меня. Я не обязан отвечать на ваши вопросы и не собираюсь - person Tim; 04.04.2018
comment
@Nethra, если этот ответ полезен, отметьте этот ответ как правильный - person immodi; 04.04.2018