如何在 2021 年使用融合位置提供程序客户端快速且仅获取一次位置

How to get location fast and only once using fused location provider client in 2021

我正在开发一个应用程序,它必须尽可能快地获取设备的位置信息(纬度和经度)一次。我的代码花费了太多时间。获取位置大约需要 2-3 分钟。特别是对于那些位置按钮最初处于关闭状态的设备。我碰巧看到一个相关的问题 但那已经快 6 年了,我认为答案在 2021 年是合适的。我的情况也一样,我还需要收集经纬度信息(仅一次) 这样我就可以找到 2 个设备之间的距离。请找到我用于纬度和经度信息的代码,请告诉我是否有更好的方法来完成我的任务。使用此代码,我将在文本视图中显示当前位置(代码中的 BuyerArea),一旦正确显示位置,我将在 firebase 数据库中保存纬度和经度信息

` public class BuyerAreaFinderActivity 扩展 AppCompatActivity {

String currentGroupName, BuyerLatitude,BuyerLongitude;
Button BuyerAreaFetchBtn, continueBtn;
TextView BuyerArea; // to display location
private FirebaseUser User;
private Task<Void> UserTask;
private FirebaseAuth mAuth;
private DatabaseReference RootRef;
private String currentUserId;
FusedLocationProviderClient fusedLocationProviderClient;

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

    BuyerAreaFetchBtn= findViewById(R.id.buyAfBtn);
    continueBtn=findViewById(R.id.continueBtn);

    BuyerArea=findViewById(R.id.tv_address);
    mAuth=FirebaseAuth.getInstance();
    currentUserId=mAuth.getCurrentUser().getUid();

    RootRef= FirebaseDatabase.getInstance().getReference();


    fusedLocationProviderClient= LocationServices.getFusedLocationProviderClient(
            BuyerAreaFinderActivity.this);

    BuyerAreaFetchBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (!isConnected(this)) { // checking internet connection

                Toast.makeText(getApplicationContext(), " Please connect to internet", Toast.LENGTH_SHORT).show();

            }else {


                LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE
                );
                if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
                        || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {

                    if (ActivityCompat.checkSelfPermission(BuyerAreaFinderActivity.this
                            , Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                            && ActivityCompat.checkSelfPermission(BuyerAreaFinderActivity.this
                            , Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED){

                        getCurrentLocation();

                    }else {
                        //when permission is not granted
                        //Request permission
                        ActivityCompat.requestPermissions(BuyerAreaFinderActivity.this
                                , new String[]{Manifest.permission.ACCESS_FINE_LOCATION
                                        , Manifest.permission.ACCESS_COARSE_LOCATION}
                                , 100);
                    }

                }else {
                    Toast.makeText(getApplicationContext(), "Please switch on location , We will be sending enquiry to bet shops in your location ", Toast.LENGTH_LONG).show();
                    startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
                            .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
                }

            }
        }
    });

    BuyerArea.addTextChangedListener(new TextWatcher() { //Here I am displaying location, Once displayed correctly I will save latitude and longitude in my database
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) { Here I am displaying location, Once displayed correctly I will save latitude and longitude in my database


            HashMap<String, Object>buyerLocationMap = new HashMap<>();
            buyerLocationMap.put("buyerLatitude", BuyerLatitude);
            buyerLocationMap.put("buyerLongitude", BuyerLongitude);

            RootRef.child("Users").child(currentUserId).updateChildren(buyerLocationMap)
            .addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                   if(task.isSuccessful()){

                       continueBtn.setVisibility(View.VISIBLE);
                       continueBtn.setEnabled(true);

                   }else {
                       String ErrorMessage = task.getException().toString(); // get the error ocuured  from net/firebase
                       Toast.makeText(BuyerAreaFinderActivity.this, "Error : " + ErrorMessage, Toast.LENGTH_SHORT).show();

                   }


                }
            });




        }
    });

    continueBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            SendToNextActivity(); // next activity 
            finish();

        }
    });
}



@SuppressLint("MissingSuperCall")
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

    //This methood check whether permmission is granted or not after requesting permission using the request code

    //here suppress error by right clicking.
    if(requestCode ==100 && grantResults.length>0&&(grantResults[0]+grantResults[1]
            ==PackageManager.PERMISSION_GRANTED)){
        //when permission granted
        // Call method
        getCurrentLocation();


    }else {
        //when permissions are denied

        if (!ActivityCompat.shouldShowRequestPermissionRationale(BuyerAreaFinderActivity.this, Manifest.permission.ACCESS_FINE_LOCATION )
                && !ActivityCompat.shouldShowRequestPermissionRationale(BuyerAreaFinderActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION)) {
            //This block here means PERMANENTLY DENIED PERMISSION
            new AlertDialog.Builder(BuyerAreaFinderActivity.this)
                    .setMessage("You have permanently denied this permission, go to settings to enable this permission")
                    .setPositiveButton("Go to settings", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            gotoApplicationSettings();
                        }
                    })
                    .setNegativeButton("Cancel", null)
                    .setCancelable(false)
                    .show();
        }else{
            Toast.makeText(getApplicationContext(),"Location permission denied, Please click again to allow location permission.",Toast.LENGTH_LONG).show();
        }
    }
}

@SuppressLint("MissingPermission")

private void getCurrentLocation() {

    fusedLocationProviderClient.flushLocations();// used by me for refreshing don't know correct or not


    fusedLocationProviderClient.getLastLocation().addOnCompleteListener(new OnCompleteListener<Location>() {
        @Override
        public void onComplete(@NonNull Task<Location> task) {

            Location location=task.getResult();
            //Check condition
            if(location !=null){

                BuyerLatitude=String.valueOf(location.getLatitude());
                BuyerLongitude=String.valueOf(location.getLongitude());

/ ------------------ Geocoder 用于查找地址,如果我们不想显示地址,请不要使用此部分 ------ ----------

                Geocoder geocoder = new Geocoder(BuyerAreaFinderActivity.this, Locale.getDefault());
                try {
                    List<Address> addresses = geocoder.getFromLocation(location.getLatitude(),location.getLongitude(),1);
                    String address = addresses.get(0).getAddressLine(0);
                    BuyerArea.setText(address);
                    BuyerAreaFetchBtn.setVisibility(View.INVISIBLE);

                } catch (IOException e) {
                    e.printStackTrace();
                }
                //------------------up to here for Geocoder-------------------------------------------------------------------------------


            }
            else {
                //Location update.. when location result is null , Initialize location update part
                // LocationRequest locationRequest = new LocationRequest() //deprecated so changed by me

                LocationRequest locationRequest = LocationRequest.create()
                        .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
                        .setInterval(10000)
                        .setFastestInterval(1000)
                        .setNumUpdates(1);

                //Initialize location call back

                LocationCallback locationCallback=new LocationCallback(){
                    @Override
                    public void onLocationResult(LocationResult locationResult) {
                        Location location1=locationResult.getLastLocation();

                        BuyerLatitude=String.valueOf(location1.getLatitude());
                        BuyerLongitude=String.valueOf(location1.getLongitude());
                    }
                };
                // Request location updates, Actually I dont want location updates but removal caused further delay in fetching location.
                
                fusedLocationProviderClient.requestLocationUpdates(locationRequest,locationCallback, Looper.myLooper());
                Toast.makeText(getApplicationContext(),"We are collecting your location details. Please wait for few seconds and press the button again",Toast.LENGTH_LONG).show();

                fusedLocationProviderClient.removeLocationUpdates(locationCallback);


            }

        }
    });


}

private void gotoApplicationSettings() { // if location is off, this will allow us to open the settings

    Intent intent = new Intent();
    intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    Uri uri = Uri.fromParts("package", this.getPackageName(), null);
    intent.setData(uri);
    startActivity(intent);

}

private boolean isConnected(View.OnClickListener onClickListener) {

    ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo wifiConn = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
    NetworkInfo mobileConn = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
    return (wifiConn != null && wifiConn.isConnected()) || (mobileConn != null && mobileConn.isConnected());
}

private void SendToNextActivity() {


    Intent nextIntent = new Intent(Current.this, Next.class); // Take to next activity
          startActivity(nextIntent);
          finish();
}

}`

     private void getUserLastLocation(FusedLocationProviderClient fusedLocationProviderClient) {
    
            if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                    ActivityCompat.checkSelfPermission(getContext(), 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.
                Toast.makeText(getContext(), "permission deny before", Toast.LENGTH_SHORT).show();
                checkSelfLoctionPermission();
            }
    
     //this logic you can write seprate to check user is enable the gps or not 
     //make sure before calling the location user has enabled the gps ..this 
     //if... else condition to help to check user has enabled gps or not
    
     if (isLocationEnabled())//if 2
                            {

        //u can write your logic here
}else
{
  Toast.makeText(getContext(), "Please turn on" + " your location...", Toast.LENGTH_LONG).show();
                                Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                                startActivity(intent);
 
}

    
                 //this if condition only run once.. when first time user want to take location
                //this method will get fresh location (means current location)
            if (!Constant.FETCHINGLOCTIONFIRSTTIEME) {
                CancellationTokenSource tokenSource = new CancellationTokenSource();
                CancellationToken token = tokenSource.getToken();
                mFusedLocationProviderClient.
                        getCurrentLocation(LocationRequest.PRIORITY_HIGH_ACCURACY, token)
                        .addOnSuccessListener(new OnSuccessListener<Location>() {
                            @Override
                            public void onSuccess(@NonNull Location location) {
    
                                if (location != null) {
                                 
                                     double lat=location.getLatitude();
                                     double longt=location.getLongitude();
    
    
                                } else {
                                   //don't be confused with AlertDialoBox because 
            //this our alerbox written by me you can write own alerbox to show the //message 
                                    Common.AlertDialogBox(getContext(), "Fetching location ",
                                            getString(R.string.fetchingerror));
    
    
                                }
    
    
                            }
                        }).addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
    
                        String message = e.getMessage();
                        String title = "locatuion fetching exception";
                        Common.AlertDialogBox(getContext(), title, message);
    
                    }
                });
            } else {
    
                fusedLocationProviderClient.getLastLocation()
                        .addOnSuccessListener(new OnSuccessListener<Location>() {
                            @Override
                            public void onSuccess(@NonNull Location location) {
                                if (location != null) {
                                    double lat=location.getLatitude();
                                double longt=location.getLongitude();
                                } else {
                                    Toast.makeText(getContext(), "Fetching location error", Toast.LENGTH_SHORT).show();
                                    Log.d("test", "onViewCreated" + "fetching location error");
    
    
                                }
                            }
                        }).addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        String message = e.getMessage();
                        String title = "locatuion fetching exception";
                     
                    }
                });
            }//else closed
        }

  //to check user gps is o or not
    private boolean isLocationEnabled() {
        LocationManager locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    }