使用融合位置提供程序获取用户当前位置

Posted

技术标签:

【中文标题】使用融合位置提供程序获取用户当前位置【英文标题】:Getting user current location using fused location provider 【发布时间】:2019-07-28 04:13:31 【问题描述】:

我正在使用 google play service location api(融合位置提供程序)来获取用户当前位置。在某些情况下,返回结果需要太多时间,有时返回同一设备的结果需要的时间要少得多。在这两种情况下,用户都在室内。我无法理解这种情况背后的原因。

public class SelfAttendanceFragment extends Fragment implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
    OnMapReadyCallback, GoogleMap.OnMapClickListener 


protected static final int REQUEST_CHECK_SETTINGS = 0x1;
private static final int MY_PERMISSIONS_REQUEST = 1;
private static Double LATITUDE_DHAKA;
private static Double LONGITUDE_DHAKA;

LoadingDialog mLoadingDialog;
double latitude = 0;
double longitude = 0;
Handler mHandler;
CountDownTimer countDownTimer;
FusedLocationProviderClient mFusedLocationClient;
GoogleApiClient mGoogleApiClient;
LocationRequest mLocationRequest;
LocationCallback mLocationCallback;
LocationManager locationManager;
SupportMapFragment mapFragment;
Location location;
private GoogleMap mMap;
private String address;
private String remarks = "";

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 
    super.onCreateView(inflater, container, savedInstanceState);
    View view = inflater.inflate(R.layout.fragment_self_attendance, container, false);
    ButterKnife.bind(this, view);
    return view;



@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) 
    super.onViewCreated(view, savedInstanceState);
    /*if (!checkPermissionGranted()) 
        askForPermission();
    */

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
        if (getActivity().checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)
                != PackageManager.PERMISSION_GRANTED

                && getActivity().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED ) 

            requestPermissions(new String[]Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.ACCESS_COARSE_LOCATION,
                    MY_PERMISSIONS_REQUEST);
         else 
               startAction();
        
     else 
        startAction();
    




private void startAction()
    mLoadingDialog = new LoadingDialog(getContext(), getString(R.string.fetching_location));

    mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
    mFusedLocationClient = LocationServices.getFusedLocationProviderClient(getContext());
    locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);

    doCheckPermissionForGps();

    mLocationCallback = new LocationCallback() 
        @Override
        public void onLocationResult(LocationResult locationResult) 
            super.onLocationResult(locationResult);
            List<Location> locationList = locationResult.getLocations();
            for (Location loc : locationList) 
                if (loc.getLatitude() != 0 && loc.getLongitude() != 0) 
                    location = loc;
                    checkLocationandAddToMap();
                     break;
                
            

        
    ;



private void doCheckPermissionForGps() 

    Boolean isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

    if (isGpsEnabled && mGoogleApiClient != null) 
        requestLocationUpdates();
     else if (mGoogleApiClient == null) 
        buildGoogleApiClient();
     else if (!isGpsEnabled) 
        displayLocationSettingsRequest(getContext());
    



protected synchronized void buildGoogleApiClient() 
    mGoogleApiClient = new GoogleApiClient.Builder(getContext())
            .addApi(LocationServices.API)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .build();
    mGoogleApiClient.connect();

    mLocationRequest = LocationRequest.create();
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    mLocationRequest.setInterval(10);
    mLocationRequest.setFastestInterval(10 / 2);


private String getAddressByLattitudeAndLongitude() 
    String address;
    try 
        Geocoder geocoder;
        List<Address> addresses;
        geocoder = new Geocoder(getContext(), Locale.getDefault());

        addresses = geocoder.getFromLocation(latitude, longitude, 5); // Here 1 represent max location result to returned, by documents it recommended 1 to 5

        address = addresses.get(0).getAddressLine(0); // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
        if (address.isEmpty()) 
            address = addresses.get(0).getLocality();
        
     catch (Exception ex) 
        address = "";
    
    return address;


private void displayLocationSettingsRequest(Context context) 
    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(mLocationRequest);
    builder.setAlwaysShow(true);

    PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
    result.setResultCallback(new ResultCallback<LocationSettingsResult>() 
        @Override
        public void onResult(LocationSettingsResult result) 
            final Status status = result.getStatus();
            switch (status.getStatusCode()) 
                case LocationSettingsStatusCodes.SUCCESS:
                    break;
                case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
                    try 
                        status.startResolutionForResult(getActivity(), REQUEST_CHECK_SETTINGS);
                     catch (IntentSender.SendIntentException e) 
                    
                    break;
                case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
                    break;
            
        
    );





 @SuppressLint("MissingPermission")
private void requestLocationUpdates() 
    if(isAdded() && getActivity() != null)
        mLoadingDialog.showDialogWithText("Fetching location using GPS...");
    

    mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());


@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) 

    super.onActivityResult(requestCode,resultCode,data);
    switch (resultCode) 
        case -1:
            requestLocationUpdates();

            break;
        case 0:
            displayLocationSettingsRequest(getContext());
            break;
        default:
            super.onActivityResult(requestCode, resultCode, data);
            break;
    




@Override
public void onConnected(@Nullable Bundle bundle) 
    if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) 
        displayLocationSettingsRequest(getContext());
     else 
        requestLocationUpdates();
    


@Override
public void onConnectionSuspended(int i) 



@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) 



@Override
public void onDestroy() 
    super.onDestroy();
    if (mFusedLocationClient != null) 
        mFusedLocationClient.removeLocationUpdates(mLocationCallback);
    


@SuppressLint("MissingPermission")
@Override
public void onMapReady(GoogleMap googleMap) 

    try
        mMap = googleMap;
        mMap.clear();

        LATITUDE_DHAKA = 23.777176;
        LONGITUDE_DHAKA = 90.399452;
        try 

            boolean success = mMap.setMapStyle(
                    MapStyleOptions.loadRawResourceStyle(
                            getContext(), R.raw.style_map));


         catch (Resources.NotFoundException e) 
            e.printStackTrace();
        

        CameraPosition camPosition = new CameraPosition.Builder()
                .target(new LatLng(LATITUDE_DHAKA, LONGITUDE_DHAKA)).zoom(10)                   // Sets the zoom
                // Sets the orientation of the camera to east
                .build();

        if (mMap != null)
            mMap.animateCamera(CameraUpdateFactory
                    .newCameraPosition(camPosition));

        mMap.setMyLocationEnabled(true);
        mMap.setOnMyLocationButtonClickListener(new GoogleMap.OnMyLocationButtonClickListener() 
            @Override
            public boolean onMyLocationButtonClick() 
                doCheckPermissionForGps();
                return false;
            
        );


        View locationButton = ((View) mapFragment.getView().findViewById(Integer.parseInt("1")).getParent()).findViewById(Integer.parseInt("2"));
        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)
                locationButton.getLayoutParams();
        // position on right bottom
        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0);
        layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
        layoutParams.setMargins(0, 0, 0, 100);
     catch (Exception ex)

    





private void checkLocationandAddToMap() 

    //MarkerOptions are used to create a new Marker.You can specify location, title etc with MarkerOptions
    if (location != null) 

        CameraPosition camPosition = new CameraPosition.Builder()
                .target(new LatLng(location.getLatitude(), location.getLongitude())).zoom(17)                   // Sets the zoom
                // Sets the orientation of the camera to east
                .build();

        if (mMap != null)
            mMap.animateCamera(CameraUpdateFactory
                    .newCameraPosition(camPosition));

    


@Override
public void onMapClick(LatLng latLng) 


@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
                                       int[] grantResults) 
    if (requestCode == MY_PERMISSIONS_REQUEST
            && grantResults[0] == PackageManager.PERMISSION_GRANTED

            && grantResults[1] == PackageManager.PERMISSION_GRANTED) 
        startAction();
     else 
        CustomSnackbarError.showMessageFromFragment(getContext(),"Permission is necessary" +
                " to enable this feature");
        requestPermissions(new String[]Manifest.permission.ACCESS_FINE_LOCATION,
                        Manifest.permission.ACCESS_COARSE_LOCATION,
                MY_PERMISSIONS_REQUEST);
    


/*@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) 
    switch (requestCode) 
        case MY_PERMISSIONS_REQUEST: 
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED
                    && grantResults[1] == PackageManager.PERMISSION_GRANTED
                   *//* && grantResults[2] == PackageManager.PERMISSION_GRANTED
                    && grantResults[3] == PackageManager.PERMISSION_GRANTED
                    && grantResults[4] == PackageManager.PERMISSION_GRANTED
                    && grantResults[5] == PackageManager.PERMISSION_GRANTED
                    && grantResults[6] == PackageManager.PERMISSION_GRANTED
                    && grantResults[7] == PackageManager.PERMISSION_GRANTED*//*
                    ) 

                //checkForUpdate();
                startAction();

            
            return;
        

        // other 'case' lines to check for other
        // permissions this app might request
    
*/

private boolean checkPermissionGranted() 

  /*  if (ContextCompat.checkSelfPermission(getContext(),
            Manifest.permission.ACCESS_NETWORK_STATE)
            != PackageManager.PERMISSION_GRANTED) 
        return false;
    

    if (ContextCompat.checkSelfPermission(getContext(),
            Manifest.permission.INTERNET)
            != PackageManager.PERMISSION_GRANTED) 
        return false;
    */

   /* if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.CALL_PHONE)
            != PackageManager.PERMISSION_GRANTED) 
        return false;
    

    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.CAMERA)
            != PackageManager.PERMISSION_GRANTED) 
        return false;
    

    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) 
        return false;
    

    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) 
        return false;
    */
    if (ContextCompat.checkSelfPermission(getContext(),
            Manifest.permission.ACCESS_COARSE_LOCATION)
            != PackageManager.PERMISSION_GRANTED) 
        return false;
    

    if (ContextCompat.checkSelfPermission(getContext(),
            Manifest.permission.ACCESS_FINE_LOCATION)
            != PackageManager.PERMISSION_GRANTED) 
        return false;
    
    return true;


private void askForPermission() 

    ActivityCompat.requestPermissions((Activity) getContext(),
            new String[]
                    /*Manifest.permission.ACCESS_NETWORK_STATE,
                    Manifest.permission.INTERNET,
                    Manifest.permission.CALL_PHONE,
                    Manifest.permission.CAMERA,
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,*/
                    Manifest.permission.ACCESS_COARSE_LOCATION,
                    Manifest.permission.ACCESS_FINE_LOCATION,
            ,
            MY_PERMISSIONS_REQUEST);


@Override
public void onDestroyView() 
    super.onDestroyView();
    dismisLoadingDialog();

private void dismisLoadingDialog()
    if(mLoadingDialog != null && mLoadingDialog.isShowing())
        mLoadingDialog.dismiss();
    

【问题讨论】:

【参考方案1】:

大多数情况下,当用户在建筑物内时,GPS 提供商会花费大量时间来获取位置。在这种情况下,您必须从网络提供商处获取位置以获得更快的结果。 GPS 在建筑物外工作得很好,但很难从建筑物内获取位置。请允许从网络和 GPS 提供商获取位置以获得更好的结果。

【讨论】:

【参考方案2】:

android 实现和创建这个 fusedlocationprovider 库的方式是它需要两种类型的位置更新: 1 -> 基于网络 2 -> 全球定位系统

当用户尝试从室内或 GPS 没有太多空间从卫星获取位置的任何地方获取位置时,它使用网络。

因此,当您在室内工作时,您会发现获取位置很麻烦。但正如你所说,有时需要更少的时间,有时需要很多时间。

可能的情况是,每当您请求位置时,如果其他应用程序已经获取了位置,它就会去尝试查找位置,并且如果有位置,您就会得到它。否则它会尝试自己找到位置,下次你搜索它时它会直接给你。

并且您已经使用了 GPS 提供商,也使用了网络提供商。

如果有帮助,请告诉我。谢谢

【讨论】:

以上是关于使用融合位置提供程序获取用户当前位置的主要内容,如果未能解决你的问题,请参考以下文章

Android 融合位置更新

Android 中的融合位置提供程序

Android 融合位置提供程序设置

使用融合的 Location Provider 获取当前位置

获取棉花糖中的当前位置 0,其中 23 API 以下使用融合位置给出准确的当前位置

当应用程序和设备中的 Google Play 服务不同时,使用融合位置获取 CurrentLocation 0