通过位置服务警报打开位置后等待位置打开

Waiting until location is on after turning it on through location services alert

我遇到一个问题,如果我的 phone 的定位服务被关闭,我想设置一个警报以打开定位服务设置并在那里打开它。这工作正常,但问题是当我打开它后导航回我的应用程序时。似乎当我单击返回时,我的 activity 的 onResume 被调用,但在 onResume 完成之前,位置仍然没有正确设置。这是我的代码:

Comments.java:

@Override
public void onResume() {
    super.onResume();
    locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
    Location location = LocationService.getLastLocation();
    if(location == null) {
        if(getLastKnownLocation() == null) {
            if(checkLocationEnabled()); {
                location = getLastKnownLocation();
            }
        }
    }

    if(location != null) {
        progressOverlay = fragmentView.findViewById(R.id.progress_overlay);
        AndroidUtils.animateView(progressOverlay, View.VISIBLE, 0.9f, 200);
        //Within this function call, the progress overlay is set to View.GONE.
        databaseQuery.getPublicPosts(location, progressOverlay, fragmentView, getContext());
    } else {
        //We need to handle an error saying that location is not enabled for this device and exit them out of the app
    }
}

private Location getLastKnownLocation() {
    locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
    List<String> providers = locationManager.getProviders(true);
    Location bestLocation = null;
    for (String provider : providers) {
        if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

            return null;
        } else {
            Location l = locationManager.getLastKnownLocation(provider);
            if (bestLocation == null || l.getAccuracy() < bestLocation.getAccuracy()) {
                // Found best last known location: %s", l);
                bestLocation = l;
            }
        }
    }

    return bestLocation;
}

public boolean checkLocationEnabled() {
    try {
        gps_enabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    } catch(Exception ex) {
    }
    try {
        network_enabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    } catch(Exception ex) {

    }
    if(!gps_enabled && !network_enabled) {
        // notify user
        AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
        dialog.setMessage(getContext().getResources().getString(R.string.gpsNetworkNotEnabled));
        dialog.setPositiveButton(getContext().getResources().getString(R.string.openLocationSettings), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface paramDialogInterface, int paramInt) {
                Intent myIntent = new Intent( Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                getContext().startActivity(myIntent);
                //get gps
            }
        });
        dialog.setNegativeButton(getContext().getString(R.string.cancel), new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface paramDialogInterface, int paramInt) {

            }
        });
        dialog.show();
    }
    return gps_enabled || network_enabled;
}

我所做的是当 phone 定位服务关闭时,我设置了一个提醒,将您带到定位服务屏幕。当用户打开位置服务屏幕时,如果他或她在他或她的 phone 上单击 "back",他们应该被带回到显示他们的位置服务处于关闭状态的初始屏幕。但是,当导航回该屏幕时,我的 progressOverlay 变量仍然可见,因为 databaseQuery.getPublicPosts 调用通过时 progressOverlay 设置为 View.GONE。这似乎并没有发生,因为当我们导航回屏幕时 if(location != null) 语句可能是错误的,但在 phone 等待几秒钟并完全获得 phone的位置。这很有趣,因为如果我在该代码中的任何地方放置一个调试器,位置服务将被正确设置并且我的 progressOverlay 将消失,因为在我调试代码时位置已设置。在调用 databaseQuery.getPublicPosts 之前,有什么方法可以 "wait" 或继续显示加载屏幕直到位置服务完全打开?任何帮助将不胜感激。

首先,您在 if(checkLocationEnabled()); 中有一个不需要的分号,它充当空语句,导致对 getLastKnownLocation() 的第二次调用始终执行(这很可能不会影响问题)。

LocationManager class 有一个常量 KEY_STATUS_CHANGED that is the key of a bundle extra that is passed when a status change is broadcast. See the documentation related to the constant. To trigger this change you need to call [LocationManager.requestLocationUpdates](https://developer.android.com/reference/android/location/LocationManager.html#requestLocationUpdates(long, float, android.location.Criteria, android.app.PendingIntent)) 以便位置管理器接收这样的状态更新.

根据此方法的文档,您可以使用 BroadcastReceiver 通过过滤上述常量来接收更新。 Here 是执行此操作的相关 post。或者您可以使用请求更新方法的另一个重载版本,该方法采用 LocationListener 并具有 onStatusChanged 回调。

启用位置提供程序时存在类似的更新,KEY_PROVIDER_ENABLED。如果状态更新不起作用,您可以尝试监听这两个更新。

请注意,当请求提供者的位置更新时,为了包括所有提供者的更新,包括 disabled 提供者,您应该使用 LocationManager.getProviders(false).[=23 检索它们=]

收到适当的更新事件后,您可以调用 removeUpdates 删除更新请求。

嗨,为什么要尝试使用 getLastKnownLocation。它 return 您之前的纬度和经度,可能需要一些时间来更新 lastknown location。 很可能它会在到达您的位置后返回 null。

我只是指你 google 融合 api 定位任何类型的更新或 current.Its 非常准确。

如何在 project.See 中融合 api 我会给你举个小例子。

第 1 步. 使这个 class GoogleLocationService.java

public class GoogleLocationService {
private GoogleServicesCallbacks callbacks = new GoogleServicesCallbacks();
LocationUpdateListener locationUpdateListener;
Context activity;
protected GoogleApiClient mGoogleApiClient;
protected LocationRequest mLocationRequest;

public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 30000;


public GoogleLocationService(Context activity, LocationUpdateListener locationUpdateListener) {
    this.locationUpdateListener = locationUpdateListener;
    this.activity = activity;
    buildGoogleApiClient();
}

protected synchronized void buildGoogleApiClient() {
    //Log.i(TAG, "Building GoogleApiClient");
    mGoogleApiClient = new GoogleApiClient.Builder(activity)
            .addConnectionCallbacks(callbacks)
            .addOnConnectionFailedListener(callbacks)
            .addApi(LocationServices.API)
            .build();
    createLocationRequest();
    mGoogleApiClient.connect();
}

protected void createLocationRequest() {
    mLocationRequest = new LocationRequest();
    mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

}

private class GoogleServicesCallbacks implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {

    @Override
    public void onConnected(Bundle bundle) {
        startLocationUpdates();
    }

    @Override
    public void onConnectionSuspended(int i) {
        mGoogleApiClient.connect();
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

        if (connectionResult.getErrorCode() == ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED) {
            Toast.makeText(activity, "Google play service not updated", Toast.LENGTH_LONG).show();

        }
        locationUpdateListener.cannotReceiveLocationUpdates();
    }

    @Override
    public void onLocationChanged(Location location) {
        if (location.hasAccuracy()) {
            if (location.getAccuracy() < 30) {
                locationUpdateListener.updateLocation(location);
            }
        }
    }
}

private static boolean locationEnabled(Context context) {
    boolean gps_enabled = false;
    LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
    try {
        gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return gps_enabled;
}

private boolean servicesConnected(Context context) {
    return isPackageInstalled(GooglePlayServicesUtil.GOOGLE_PLAY_STORE_PACKAGE, context);
}

private boolean isPackageInstalled(String packagename, Context context) {
    PackageManager pm = context.getPackageManager();
    try {
        pm.getPackageInfo(packagename, PackageManager.GET_ACTIVITIES);
        return true;
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
        return false;
    }
}


public void startUpdates() {
    /*
     * Connect the client. Don't re-start any requests here; instead, wait
     * for onResume()
     */
    if (servicesConnected(activity)) {
        if (locationEnabled(activity)) {
            locationUpdateListener.canReceiveLocationUpdates();
            startLocationUpdates();
        } else {
            locationUpdateListener.cannotReceiveLocationUpdates();
            Toast.makeText(activity, "Unable to get your location.Please turn on your device Gps", Toast.LENGTH_LONG).show();
        }
    } else {
        locationUpdateListener.cannotReceiveLocationUpdates();
        Toast.makeText(activity, "Google play service not available", Toast.LENGTH_LONG).show();
    }
}

//stop location updates
public void stopUpdates() {
    stopLocationUpdates();
}

//start location updates
private void startLocationUpdates() {

    if (checkSelfPermission(activity, ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(activity, ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        return;
    }
    if (mGoogleApiClient.isConnected()) {
        LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, callbacks);
    }
}

public void stopLocationUpdates() {
    if (mGoogleApiClient.isConnected()) {
        LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, callbacks);
    }
}

public void startGoogleApi() {
    mGoogleApiClient.connect();
}

public void closeGoogleApi() {
    mGoogleApiClient.disconnect();
}

 }

第二步。做这个界面 LocationUpdateListener.java

 public interface LocationUpdateListener {

/**
 * Called immediately the service starts if the service can obtain location
 */
void canReceiveLocationUpdates();

/**
 * Called immediately the service tries to start if it cannot obtain location - eg the user has disabled wireless and
 */
void cannotReceiveLocationUpdates();

/**
 * Called whenever the location has changed (at least non-trivially)
 * @param location
 */
void updateLocation(Location location);

/**
 * Called when GoogleLocationServices detects that the device has moved to a new location.
 * @param localityName The name of the locality (somewhere below street but above area).
 */
void updateLocationName(String localityName, Location location);
}

第 3 步。在要获取位置的地方使用这段代码

public class MainActivity extends ActionBarActivity {

private GoogleLocationService googleLocationService;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    googleLocationService = new GoogleLocationService(context, new LocationUpdateListener() {
    @Override
    public void canReceiveLocationUpdates() {
    }

    @Override
    public void cannotReceiveLocationUpdates() {
    }

    //update location to our servers for tracking purpose
    @Override
    public void updateLocation(Location location) {
        if (location != null ) {
            Timber.e("updated location %1$s %2$s", location.getLatitude(), location.getLongitude());

        }
    }

    @Override
    public void updateLocationName(String localityName, Location location) {

        googleLocationService.stopLocationUpdates();
    }
});
googleLocationService.startUpdates();


}

@Override
public void onDestroy() {
    super.onDestroy();
if (googleLocationService != null) {
    googleLocationService.stopLocationUpdates();
}

}
}

更新答案 如何通过广播发送和接收lat lng

将此称为位置已更改

Intent sendBroadIntentPND = new Intent("COORD_BROADCAST_FILTER");
                    sendBroadIntentPND.putExtra("LOC_LAT", location.getLatitude());
sendBroadIntentPND.putExtra("LOC_LON", location.getLongitude());
getApplicationContext().sendBroadcast(sendBroadIntentPND);

那么你要在哪里接收定位电话呢

// declear global variable
private final String COORD_BROADCAST_FILTER = "COORD_BROADCAST_FILTER";
private Location newLocation;

private BroadcastReceiver coordinateReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
try {
            newLocation.setLatitude(intent.getDoubleExtra("LOC_LAT", 0.0));
            newLocation.setLongitude(intent.getDoubleExtra("LOC_LON", 0.0));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

 };

在创建时注册您的接收器,

 getActivity().registerReceiver(coordinateReceiver, new IntentFilter(COORD_BROADCAST_FILTER));

在销毁时取消注册您的接收器

 getActivity().unregisterReceiver(coordinateReceiver);

谢谢,希望对你有帮助。

请注意

The Google Play services location APIs are preferred over the Android framework location APIs (android.location) as a way of adding location awareness to your app. If you are currently using the Android framework location APIs, you are strongly encouraged to switch to the Google Play services location APIs as soon as possible.