简体   繁体   English

Android 中的后台位置定期更新

[英]Background location update in Android periodically

I am Using Fused Location Provider Google api client to get the location for every 5 minutes .我正在使用 Fused Location Provider Google api 客户端每 5 分钟获取一次位置。 It is updating both in background and also when the application is killed .它在后台和应用程序被终止时都在更新。 But it is Stopped updating after some 2 to 3 days .但它在一些 2 到 3 天后停止更新。 i have tested in most of the android devices.我已经在大多数 android 设备上进行了测试。

I am calling this Service from an Activity and i am Killing the application, it is sending location updates for every 5 minutes for almost 3 days after that it is getting stopped .I tried So many times.我正在从活动中调用此服务,并且正在终止该应用程序,它在停止后近 3 天内每 5 分钟发送一次位置更新。我尝试了很多次。

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

you can create service for do this您可以为此创建服务

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

    }

and service for location和位置服务

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

Use workmanager to reschedule your location service.使用 workmanager 重新安排您的位置服务。 Check if location service not running then start from scheduler.检查位置服务是否未运行,然后从调度程序启动。 To read more regarding workmanager click here要阅读有关工作经理的更多信息, 请单击此处

For that, you can use AlarmManager or firebase jobdispatcher orjob scheduler to trigger any event after specific intervals.为此,您可以使用AlarmManagerfirebase jobdispatcher作业调度程序在特定时间间隔后触发任何事件。 I suggest you to use AlarmManager which are easiest.我建议您使用最简单的AlarmManager

Refer this code to set alarm:参考此代码设置闹钟:

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

And you can cancel alarm like this way:你可以这样取消闹钟

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

Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use.注意:从 API 19 (KITKAT) 开始传递警报是不准确的:操作系统将转移警报以最大程度地减少唤醒和电池使用。 There are new APIs to support applications which need strict delivery guarantees;有新的 API 来支持需要严格交付保证的应用程序; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent).请参阅 setWindow(int, long, long, PendingIntent) 和 setExact(int, long, PendingIntent)。 Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested. targetSdkVersion 早于 API 19 的应用程序将继续看到以前的行为,其中所有警报都在请求时准确传递。

Create a class for location 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);
    }
}

in onLocation(Location location) change method you will get current let,long在 onLocation(Location location) 更改方法中,您将获得当前的 le​​t,long

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM