如何在Android地图中获得连续的位置更新?

时间:2017-01-06 07:13:15

标签: android gps location

我正在建立一个跟踪Android应用的朋友。当我的朋友激活应用程序并随着他的GPS和手机数据一起离开时,我需要在我的设备上跟踪他。这就是概念。

我已经实现了LocationListener类,现在我可以从Gps或网络获取最后更新的位置,但除非我启动Google Maps并返回我的应用程序,否则不会更新。在谷歌搜索后,我了解到位置缓存仅由GMaps更新。!

  1. 是否有其他方法可以持续更新位置?
  2. 如果在没有使用Wakelock的情况下锁定设备后需要继续定位,该怎么办?
  3. 这是我的位置监听器类:

    package com.amazinginside;
    
    /** AMAZING LOCATION SUPPORT CLASS, Devoloped By SANGEETH NANDAKUMAR */
    
    import android.app.AlertDialog;
    import android.app.Service;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.location.Location;
    import android.location.LocationListener;
    import android.location.LocationManager;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.provider.Settings;
    
    public class AmazingLocation extends Service implements LocationListener
    {
        private final Context mContext;
        boolean isGPSEnabled = false;
        boolean isNetworkEnabled = false;
        boolean canGetLocation = false;
    
        Location location;
        double latitude=0.0;
        double longitude=0.0;
    
        //MINIMUM DISTANCE FOR UPDATE (meters)
        private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 0; // 0 Meters
    
        //MINIMUM TIME BETWEEN UPDATES
        private static final long MIN_TIME_BW_UPDATES = 1000 * 0; // 0 Seconds
    
        //LOCATION MANAGER
        protected LocationManager locationManager;
    
        //CONSTRUCTOR
        public AmazingLocation(Context context)
        {
            this.mContext = context;
            getLocation();
        }
    
        //LOCATION PROVISION
        public Location getLocation()
        {
            try
            {
                //GET LOCATION MANAGER
                locationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
                //CHECK GPS STATE
                isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
                //CHECK NETWORK STATE
                isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    
                if (!isGPSEnabled && !isNetworkEnabled)
                {
                    //NO LOCATION PROVIDERS
                }
                else
                {
                    this.canGetLocation = true;
    
                    /** GET LOCATION FROM NETWORK */
                    //FIRST GET LOCATION FROM NETWORK
                    if (isNetworkEnabled)
                    {
                        //REQUEST LOCATION
                        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
                        if (locationManager != null)
                        {
                            //START WITH LAST KNOWN LOCATION
                            location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
                            //EXTRACT LOCATION
                            if (location != null)
                            {
                                latitude = location.getLatitude();
                                longitude = location.getLongitude();
                            }
                        }
                    }
    
                    /** GET LOCATION FROM GPS SENSOR */
                    //THEN GET LOCATION FROM GPS
                    if (isGPSEnabled)
                    {
                        if (location == null)
                        {
                            //REQUEST GPS LOCATION
                            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
    
                            if (locationManager != null)
                            {
                                //EXTRACT LAST KNOWN LOCATION
                                location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                                //RETURN LOCATION
                                if (location != null)
                                {
                                    latitude = location.getLatitude();
                                    longitude = location.getLongitude();
                                }
                            }
                        }
                    }
                }
    
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
    
            return location;
        }
    
        //STOP GPS SENSOR
        public void stopUsingGPS()
        {
            if(locationManager != null)
            {
                locationManager.removeUpdates(AmazingLocation.this);
            }
        }
    
        //EXTRACT LATTITUDE
        public double getLatitude()
        {
            if(location != null)
            {
                latitude = location.getLatitude();
            }
    
            // return latitude
            return latitude;
        }
    
        //EXTACT LONGITUDE
        public double getLongitude()
        {
            if(location != null)
            {
                longitude = location.getLongitude();
            }
    
            // return longitude
            return longitude;
        }
    
        //CAN I GET THE LOCATION.?
        public AmazingStatus canGetLocation()
        {
            AmazingStatus status=new AmazingStatus();
            if(this.canGetLocation)
            {
                status.setStatus(true);
                status.setErrorcode(0);
                status.setErrormsg("Task completed");
            }
            else
            {
                status.setStatus(false);
                status.setErrorcode(145);
                status.setErrormsg("Please turn on GPS access manually");
            }
            return status;
        }
    
        //SHOW LOCATION SETTINGS
        public AmazingStatus showSettingsAlert()
        {
            final AmazingStatus status=new AmazingStatus();
            AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
            alertDialog.setTitle("REQUIRES LOCATION ACCESS");
            alertDialog.setMessage("Please allow GPS access to this app");
    
            //POSSITIVE REPLY
            alertDialog.setPositiveButton("Allow", new DialogInterface.OnClickListener()
            {
                public void onClick(DialogInterface dialog,int which)
                {
                    Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                    mContext.startActivity(intent);
                    status.setStatus(true);
                    status.setErrorcode(0);
                    status.setErrormsg("Task completed");
                }
            });
    
            //NEGATIVE REPLY
            alertDialog.setNegativeButton("Deny", new DialogInterface.OnClickListener()
            {
                public void onClick(DialogInterface dialog, int which)
                {
                    status.setStatus(false);
                    status.setErrorcode(408);
                    status.setErrormsg("User denied permission");
                    dialog.cancel();
                }
            });
    
            // Showing Alert Message
            alertDialog.show();
            return status;
        }
    
        //UNUSED OVERRIDE METHORDS...
        @Override
        public void onLocationChanged(Location location)
        {
            getLocation();
        }
    
        @Override
        public void onProviderDisabled(String provider)
        {
        }
    
        @Override
        public void onProviderEnabled(String provider)
        {
            getLocation();
        }
    
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras)
        {
            getLocation();
        }
    
        @Override
        public IBinder onBind(Intent arg0)
        {
            return null;
        }
    
    }
    

    这是我的onCreate()方法:

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        //CREATE A BUTTON HANDLER
        Button start_btn=(Button)findViewById(R.id.start_location_streaming);
        //ON BUTTON CLICK EVENT
        start_btn.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                //REPEAT A METHORD AT SPECIFIC INTERVALS
                Timer myTimer = new Timer();
                myTimer.schedule(new TimerTask()
                {
                    @Override
                    public void run()
                    {
                        TimerMethod();
                    }
    
                }, 0, 8000);
            }
        });  }
    

    这些是其他方法:

    private void TimerMethod()
    {
        //START METHORD
        this.runOnUiThread(Timer_Tick);
    }
    
    //LOCATION REPORTING METHORD
    private Runnable Timer_Tick = new Runnable()
    {
        public void run()
        {
            Toast.makeText(MainActivity.this, "Current latitude : "+Double.toString(getLocation().latitude), Toast.LENGTH_SHORT).show();
            Toast.makeText(MainActivity.this, "Current longitude : "+Double.toString(getLocation().longitude), Toast.LENGTH_SHORT).show();
        }
    };
    
    private LatLng getLocation()
    {
        //CREATE A LOCATION CLASS INSTANCE
        AmazingLocation gps = new AmazingLocation(this);
        //RETRIVE LOCATION
        double latitude = gps.getLatitude();
        double longitude = gps.getLongitude();
        //RETURN LOCATION
        LatLng loc=new LatLng(latitude,longitude);
        return loc;
    }  
    

    现在问题是,除非我打开谷歌地图并返回,否则吐司只显示以前知道的位置而不是更新。

    对我来说,任何帮助都会很棒。

5 个答案:

答案 0 :(得分:25)

使用 Android中的融合位置提供程序设置您的间隔:

例如,创建您的活动:

public class LocationActivity extends Activity implements
        LocationListener,
        GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {

    private static final String TAG = "LocationActivity";
    private static final long INTERVAL = 1000 * 10;
    private static final long FASTEST_INTERVAL = 1000 * 5;
    Button btnFusedLocation;
    TextView tvLocation;
    LocationRequest mLocationRequest;
    GoogleApiClient mGoogleApiClient;
    Location mCurrentLocation;
    String mLastUpdateTime;

    protected void createLocationRequest() {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(INTERVAL);
        mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate ...............................");
        //show error dialog if GoolglePlayServices not available
        if (!isGooglePlayServicesAvailable()) {
            finish();
        }
        createLocationRequest();
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();

        setContentView(R.layout.activity_main);
        tvLocation = (TextView) findViewById(R.id.tvLocation);

        btnFusedLocation = (Button) findViewById(R.id.btnShowLocation);
        btnFusedLocation.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                updateUI();
            }
        });

    }

    @Override
    public void onStart() {
        super.onStart();
        if (mGoogleApiClient.isConnected()) {
            startLocationUpdates();
            Log.d(TAG, "Location update resumed .....................");
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        Log.d(TAG, "onStop fired ..............");
        mGoogleApiClient.disconnect();
        Log.d(TAG, "isConnected ...............: " + mGoogleApiClient.isConnected());
    }

    private boolean isGooglePlayServicesAvailable() {
        int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
        if (ConnectionResult.SUCCESS == status) {
            return true;
        } else {
            GooglePlayServicesUtil.getErrorDialog(status, this, 0).show();
            return false;
        }
    }

    @Override
    public void onConnected(Bundle bundle) {
        Log.d(TAG, "onConnected - isConnected ...............: " + mGoogleApiClient.isConnected());
        startLocationUpdates();
    }

    protected void startLocationUpdates() {
        PendingResult<Status> pendingResult = LocationServices.FusedLocationApi.requestLocationUpdates(
                mGoogleApiClient, mLocationRequest, this);
        Log.d(TAG, "Location update started ..............: ");
    }

    @Override
    public void onConnectionSuspended(int i) {

    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.d(TAG, "Connection failed: " + connectionResult.toString());
    }

    @Override
    public void onLocationChanged(Location location) {
        Log.d(TAG, "Firing onLocationChanged..............................................");
        mCurrentLocation = location;
        mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
        updateUI();
    }

    private void updateUI() {
        Log.d(TAG, "UI update initiated .............");
        if (null != mCurrentLocation) {
            String lat = String.valueOf(mCurrentLocation.getLatitude());
            String lng = String.valueOf(mCurrentLocation.getLongitude());
            tvLocation.setText("At Time: " + mLastUpdateTime + "\n" +
                    "Latitude: " + lat + "\n" +
                    "Longitude: " + lng + "\n" +
                    "Accuracy: " + mCurrentLocation.getAccuracy() + "\n" +
                    "Provider: " + mCurrentLocation.getProvider());
        } else {
            Log.d(TAG, "location is null ...............");
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        stopLocationUpdates();
    }

    protected void stopLocationUpdates() {
        LocationServices.FusedLocationApi.removeLocationUpdates(
                mGoogleApiClient, this);
        Log.d(TAG, "Location update stopped .......................");
    }

    @Override
    public void onResume() {
        super.onResume();
        if (mGoogleApiClient.isConnected()) {
            startLocationUpdates();
            Log.d(TAG, "Location update resumed .....................");
        }
    }
}

需要Google Play服务:

答案 1 :(得分:4)

我相信,不是重新发明轮子,您可以使用易于实施的第三方库之一,在这种情况下,电池效率。我发现的其中一个库是SmartLocation。您可以在build.gradle(app)中添加以下依赖项以开始使用库。

compile 'io.nlopez.smartlocation:library:3.2.9'

添加依赖项后,您应该重建项目以获取引用。

例如,您可以在Activity中尝试以下代码。

Button start_btn=(Button)findViewById(R.id.start_location_streaming);

Context context = start_btn.getContext();

Handler handler = new Handler();

start_btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SmartLocation.with(context).location().start(locationListener);
    }
});

OnLocationUpdatedListener locationListener = new OnLocationUpdatedListener({
    @Override
    public void onLocationUpdated(Location location) {
        double lat = location.getLatitude();
        double lng = location.getLongitude();
        handler.postDelayed(locationRunnable,8000);
    }
});

Runnable locationRunnable = new Runnable({
    @Override
    public void run() {
        SmartLocation.with(context).location().start(locationListener);
    }
});

您可以在 onStop()方法

中停止位置跟踪
@Override
public void onStop() {
    SmartLocation.with(context).location().stop();
    super.onStop();
}

SmartLocation库将为您提供超出预期的功能,只需尝试一次。

注意:确保您的应用程序确实具有ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION(两者)以获得准确的结果。不要忘记在Android 6.0及更高版本的运行时请求权限。

答案 2 :(得分:1)

要获取持续的位置更新,可以参考上面提供的答案。

但是您也可以使用 LocationServices ,它比其他方法更快,并且更容易,有效地获取位置。

此方法已退出很长时间,但请遵循提供的所有步骤

所以让我提供一个简短的工作内容:

1)在gradle应用文件中添加这两个依赖项

implementation 'com.google.android.gms:play-services-maps:17.0.0'
implementation 'com.google.android.gms:play-services-location:17.0.0'

2)将这些权限添加到applicationtag之外的清单文件中

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

3)在onCreate之外声明变量

 private FusedLocationProviderClient fusedLocationClient;
 private LocationRequest mLocationRequest;
 private LocationCallback mlocationCallback;
 private LocationSettingsRequest.Builder builder;
 private static final int REQUEST_CHECK_SETTINGS = 102;

4)现在在onCreate内:

fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
fetchLastLocation();
mlocationCallback = new LocationCallback() {
                @Override
                public void onLocationResult(LocationResult locationResult) {
                    if (locationResult == null) {
                        return;
                    }
                    for (Location location : locationResult.getLocations()) {
                        // Update UI with location data
                        // ...
                       Log.e("CONTINIOUSLOC: ", location.toString());
                    }
                };
            };

mLocationRequest = createLocationRequest();
builder = new LocationSettingsRequest.Builder()
            .addLocationRequest(mLocationRequest);
checkLocationSetting(builder);

5)没有定义fetchLastLocation方法

private void fetchLastLocation() {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                // TODO: Consider calling
                //    Activity#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 Activity#requestPermissions for more details.
//                    Toast.makeText(MainActivity.this, "Permission not granted, Kindly allow permission", Toast.LENGTH_LONG).show();
                showPermissionAlert();
                return;
            }
        }
        fusedLocationClient.getLastLocation()
                .addOnSuccessListener(this, new OnSuccessListener<Location>() {
                    @Override
                    public void onSuccess(Location location) {
                        // Got last known location. In some rare situations this can be null.
                        if (location != null) {
                            // Logic to handle location object
                            Log.e("LAST LOCATION: ", location.toString()); // You will get your last location here
                        }
                    }
                });

    }

6)现在为权限请求定义另外两种方法

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case 123: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
                    // permission was denied, show alert to explain permission
                    showPermissionAlert();
                }else{
                    //permission is granted now start a background service
                    if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                            && ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                        fetchLastLocation();
                    }
                }
            }
        }
    }

    private void showPermissionAlert(){
        if (ActivityCompat.checkSelfPermission(MainHomeActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(MainHomeActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainHomeActivity.this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 123);
        }
    }

7)现在定义createLocationRequest方法和checkLocationSetting方法:

protected LocationRequest createLocationRequest() {
        LocationRequest mLocationRequest = LocationRequest.create();
        mLocationRequest.setInterval(30000);
        mLocationRequest.setFastestInterval(10000);
        mLocationRequest.setSmallestDisplacement(30);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        return mLocationRequest;
    }

private void checkLocationSetting(LocationSettingsRequest.Builder builder) {

        SettingsClient client = LocationServices.getSettingsClient(this);
        Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());

        task.addOnSuccessListener(this, new OnSuccessListener<LocationSettingsResponse>() {
            @Override
            public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
                // All location settings are satisfied. The client can initialize
                // location requests here.
                // ...
                startLocationUpdates();
                return;
            }
        });

        task.addOnFailureListener(this, new OnFailureListener() {
            @Override
            public void onFailure(@NonNull final Exception e) {
                if (e instanceof ResolvableApiException) {
                    // Location settings are not satisfied, but this can be fixed
                    AlertDialog.Builder builder1 = new AlertDialog.Builder(mContext);
                    builder1.setTitle("Continious Location Request");
                    builder1.setMessage("This request is essential to get location update continiously");
                    builder1.create();
                    builder1.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            ResolvableApiException resolvable = (ResolvableApiException) e;
                            try {
                                resolvable.startResolutionForResult(MainHomeActivity.this,
                                        REQUEST_CHECK_SETTINGS);
                            } catch (IntentSender.SendIntentException e1) {
                                e1.printStackTrace();
                            }
                        }
                    });
                    builder1.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Toast.makeText(mContext, "Location update permission not granted", Toast.LENGTH_LONG).show();
                        }
                    });
                    builder1.show();
                }
            }
        });

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (requestCode == REQUEST_CHECK_SETTINGS) {
            if (resultCode == RESULT_OK) {
                // All location settings are satisfied. The client can initialize
                // location requests here.
                 startLocationUpdates();
            }
            else {
                checkLocationSetting(builder);
            }
        }
    }

8)现在至少定义startLocationUpdates和stopLocationUpdates方法:

public void startLocationUpdates() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                // TODO: Consider calling
                //    Activity#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 Activity#requestPermissions for more details.
                return;
            }
        }
        fusedLocationClient.requestLocationUpdates(mLocationRequest,
                mlocationCallback,
                null /* Looper */);
    }



private void stopLocationUpdates() {
        fusedLocationClient.removeLocationUpdates(mlocationCallback);
    }

注意:用类上下文替换上下文,并在类的onDestroy方法内调用stopLocationUpdates()

注意:有关更多信息或疑问,请参阅:

  

https://developer.android.com/training/location/retrieve-current   https://developer.android.com/training/location/change-location-settings   https://developer.android.com/training/location/receive-location-updates

您将在Logcat中获得您的位置。

希望这会希望您或其他人!

答案 3 :(得分:0)

您应该使用Android服务,而不是应用程序本身。通过这种方式,您可以在后台连续运行代码,即使应用程序关闭,您也会收到该位置。

https://www.tutorialspoint.com/android/android_services.htm

答案 4 :(得分:0)

该库可能会派上用场。它具有位置更新所需的所有功能,例如询问权限和设置间隔时间。

https://github.com/bikcrum/LocationUpdate