如何使用从服务中检索到的纬度和经度并在地图上显示它们?

Posted

技术标签:

【中文标题】如何使用从服务中检索到的纬度和经度并在地图上显示它们?【英文标题】:How to use latitude and longitude retrieved from a service and show them on map? 【发布时间】:2019-10-17 19:50:01 【问题描述】:

我已经定义了一个服务(即 LocationService ),它为我提供了用户当前的纬度和经度,作为 my_activity 的附加意图。现在,我想用它们在地图上显示当前位置(使用谷歌地图)。我在 mMap.animateCamera 和 mMap.moveCamera 方法中传递了这些 latlng,但它们没有显示任何标记或放大到当前位置。如果我做错了什么,请告诉我。

LocationService 和我的 MainActivity 的代码粘贴在下面:

LocationServices.java

public class LocationServicesForLocationUpdates extends Service implements LocationListener,
    GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener

private static final String TAG = LocationServicesForLocationUpdates.class.getSimpleName();

public static final String ACTION_LOCATION_BROADCAST
        = LocationServicesForLocationUpdates.class.getName() + "LocationBroadcast";

public static final String EXTRA_LATITUDE = "extra_latitude";
public static final String EXTRA_LONGITUDE = "extra_longitude";

private GoogleApiClient mLocationClient;
private LocationRequest mLocationRequest = new LocationRequest();

@Override
public int onStartCommand(Intent intent, int flags, int startId) 


    mLocationClient = new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();

    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

    mLocationRequest.setInterval(5000);
    mLocationRequest.setFastestInterval(3000);

    mLocationClient.connect();

   // return super.onStartCommand(intent, flags, startId);

    return START_STICKY;


@Override
public IBinder onBind(Intent intent) 
    return null;


/*
 * LOCATION CALLBACKS
 */
@Override
public void onConnected(Bundle dataBundle) 
    if (ActivityCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED

            && ActivityCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) 

        // 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.

        Log.d(TAG, "== Error On onConnected() Permission not granted");
        //Permission not granted by user so cancel the further execution.


        return;
    
    LocationServices.FusedLocationApi.requestLocationUpdates(mLocationClient, mLocationRequest ,this);

    Log.d(TAG, "Connected to Google API");




//to get the location change
@Override
public void onLocationChanged(Location location) 
    Log.d(TAG, "Location changed");


    if (location != null) 
        Log.d(TAG, "== location != null");

        //Send result to activities
        sendMessageToUI(String.valueOf(location.getLatitude()), String.valueOf(location.getLongitude()));

    


private void sendMessageToUI(String lat, String lng) 

    Log.d(TAG, "Sending info...");

    Intent intent = new Intent(ACTION_LOCATION_BROADCAST);
    intent.putExtra(EXTRA_LATITUDE, lat);
    intent.putExtra(EXTRA_LONGITUDE, lng);
    LocalBroadcastManager.getInstance(this).sendBroadcast(intent);



@Override
public void onConnectionSuspended(int i) 



@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) 



新建 MainActivity.java

 public class MainActivity extends AppCompatActivity implements OnMapReadyCallback

private TextView mLatlngTxtVu , mAddressTxtVu;


private boolean mAlreadyStartedService;

private static final String TAG = ParentHomeActivity.class.getSimpleName();

private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;


private GoogleMap mGoogleMap;

Double mlattitude , mlongitude;

Marker mCurrentMarker;

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


    Log.d(TAG, "onCreate: Called");
    mLatlngTxtVu = (TextView) findViewById(R.id.latlng_txtview);
    mAddressTxtVu = (TextView) findViewById(R.id.address_txtvu);

    LocalBroadcastManager.getInstance(this).registerReceiver(
            new BroadcastReceiver() 
                @Override
                public void onReceive(Context context, Intent intent) 
                    mlattitude = Double.parseDouble(intent.getStringExtra(LocationServicesForLocationUpdates.EXTRA_LATITUDE));
                    mlongitude = Double.parseDouble(intent.getStringExtra(LocationServicesForLocationUpdates.EXTRA_LONGITUDE));


                    Log.d("latlng", "onReceive: " + mlongitude + mlattitude);



                    if (mlattitude != null && mlongitude != null) 
                        mLatlngTxtVu.setText("Latitude : " + mlattitude + "Longitude: " + mlongitude);
                    
                
            , new IntentFilter(LocationServicesForLocationUpdates.ACTION_LOCATION_BROADCAST)
    );

    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.main_map);
    mapFragment.getMapAsync(MainActivity.this);



@Override
protected void onResume() 
    super.onResume();

    checkGooglePlayServices();




@Override
public void onMapReady(GoogleMap googleMap) 

    mGoogleMap = googleMap ;

    Log.d(TAG, "onMapReady: called");

    Log.d("coord", mlattitude + "   " + mlongitude);

    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;
    


    mGoogleMap.setMyLocationEnabled(true);
    mGoogleMap.getUiSettings().setMyLocationButtonEnabled(true);
    mGoogleMap.getUiSettings().setMapToolbarEnabled(false);


    CameraPosition cameraPosition = new CameraPosition.Builder()
            .target(new LatLng(mlattitude, mlongitude))      // Sets the center of the map to location user
            .zoom(14)                   // Sets the zoom
            .bearing(0)                // Sets the orientation of the camera to east
            .tilt(90)                   // Sets the tilt of the camera to 30 degrees
            .build();                   // Creates a CameraPosition from the builder
    mGoogleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));


    LatLng latLng = new LatLng(mlattitude  , mlongitude);

    mGoogleMap.addMarker(new MarkerOptions().position(latLng).title("YOU"));

   // mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));

   /* CameraPosition cameraPosition = new CameraPosition.Builder()
            .target(new LatLng(mlattitude, mlongitude))      // Sets the center of the map to location user
            .zoom(17)                   // Sets the zoom
            .bearing(90)                // Sets the orientation of the camera to east
            .tilt(40)                   // Sets the tilt of the camera to 30 degrees
            .build();                   // Creates a CameraPosition from the builder
    mGoogleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));*/





private void checkGooglePlayServices() 

    //Check whether this user has installed Google play service which is being used by Location updates.
    if (isGooglePlayServicesAvailable()) 

        //Passing null to indicate that it is executing for the first time.
        checkAndPromptForInternetConnection(null);

     else 
        Toast.makeText(getApplicationContext(), "Play services Not Available", Toast.LENGTH_LONG).show();
    



private boolean checkAndPromptForInternetConnection(DialogInterface dialog) 

    ConnectivityManager connectivityManager
            = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();

    if (activeNetworkInfo == null || !activeNetworkInfo.isConnected()) 
        promptInternetConnect();
        return false;
    


    if (dialog != null) 
        dialog.dismiss();
    

    //Yes there is active internet connection. Next check Location is granted by user or not.

    if (checkPermissions())  //Yes permissions are granted by the user. Go to the next step.
        startedLocationServices();
     else   //No user has not granted the permissions yet. Request now.
        requestPermissions();
    
    return true;


/**
 * Step 3: Start the Location Monitor Service
 */
private void startedLocationServices() 

    //And it will be keep running until you close the entire application from task manager.
    //This method will executed only once.

    if (!mAlreadyStartedService && mLatlngTxtVu != null) 

        mLatlngTxtVu.setText("Running ");

        //Start location sharing service to app server.........
        Intent intent = new Intent(this, LocationServicesForLocationUpdates.class);
        startService(intent);

        mAlreadyStartedService = true;
        //Ends................................................
    

/**
 * Show A Dialog with button to refresh the internet state.
 */
private void promptInternetConnect() 
    AlertDialog.Builder builder = new AlertDialog.Builder(ParentHomeActivity.this);
    builder.setTitle("No internet connection");
    builder.setMessage("Please Check your internet connection");

    String positiveText = "Refresh";
    builder.setPositiveButton(positiveText,
            new DialogInterface.OnClickListener() 
                @Override
                public void onClick(DialogInterface dialog, int which) 


                    //Block the Application Execution until user grants the permissions
                    if (checkAndPromptForInternetConnection(dialog)) 

                        //Now make sure about location permission.
                        if (checkPermissions()) 

                            //Step 2: Start the Location Monitor Service
                            //Everything is there to start the service.
                            startedLocationServices();
                         else if (!checkPermissions()) 
                            requestPermissions();
                        

                    
                
            );

    AlertDialog dialog = builder.create();
    dialog.show();



/**
 * Return the availability of GooglePlayServices
 */
public boolean isGooglePlayServicesAvailable() 
    GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance();
    int status = googleApiAvailability.isGooglePlayServicesAvailable(this);
    if (status != ConnectionResult.SUCCESS) 
        if (googleApiAvailability.isUserResolvableError(status)) 
            googleApiAvailability.getErrorDialog(this, status, 2404).show();
        
        return false;
    
    return true;



/**
 * Return the current state of the permissions needed.
 */
private boolean checkPermissions() 
    int permissionState1 = ActivityCompat.checkSelfPermission(this,
            android.Manifest.permission.ACCESS_FINE_LOCATION);

    int permissionState2 = ActivityCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_COARSE_LOCATION);

    return permissionState1 == PackageManager.PERMISSION_GRANTED && permissionState2 == PackageManager.PERMISSION_GRANTED;



/**
 * Start permissions requests.
 */
private void requestPermissions() 

    boolean shouldProvideRationale =
            ActivityCompat.shouldShowRequestPermissionRationale(this,
                    android.Manifest.permission.ACCESS_FINE_LOCATION);

    boolean shouldProvideRationale2 =
            ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.ACCESS_COARSE_LOCATION);


    // Provide an additional rationale to the img_user. This would happen if the img_user denied the
    // request previously, but didn't check the "Don't ask again" checkbox.
    if (shouldProvideRationale || shouldProvideRationale2) 
        Log.i(TAG, "Displaying permission rationale to provide additional context.");
        showSnackbar(R.string.grantPermission,
                android.R.string.ok, new View.OnClickListener() 
                    @Override
                    public void onClick(View view) 
                        // Request permission
                        ActivityCompat.requestPermissions(ParentHomeActivity.this,
                                new String[]android.Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION,
                                REQUEST_PERMISSIONS_REQUEST_CODE);
                    
                );
     else 
        Log.i(TAG, "Requesting permission");
        // Request permission. It's possible this can be auto answered if device policy
        // sets the permission in a given state or the img_user denied the permission
        // previously and checked "Never ask again".
        ActivityCompat.requestPermissions(ParentHomeActivity.this,
                new String[]android.Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION,
                REQUEST_PERMISSIONS_REQUEST_CODE);
    


/**
 * Shows a @link Snackbar.
 *
 * @param mainTextStringId The id for the string resource for the Snackbar text.
 * @param actionStringId   The text of the action item.
 * @param listener         The listener associated with the Snackbar action.
 */
private void showSnackbar(final int mainTextStringId, final int actionStringId,
                          View.OnClickListener listener) 
    Snackbar.make(
            findViewById(android.R.id.content),
            getString(mainTextStringId),
            Snackbar.LENGTH_INDEFINITE)
            .setAction(getString(actionStringId), listener).show();



/**
 * Callback received when a permissions request has been completed.
 */
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                       @NonNull int[] grantResults) 
    Log.i(TAG, "onRequestPermissionResult");
    if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) 
        if (grantResults.length <= 0) 
            // If img_user interaction was interrupted, the permission request is cancelled and you
            // receive empty arrays.
            Log.i(TAG, "User interaction was cancelled.");
         else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) 

            Log.i(TAG, "Permission granted, updates requested, starting location updates");
            startedLocationServices();

         else 
            // Permission denied.

            // Notify the img_user via a SnackBar that they have rejected a core permission for the
            // app, which makes the Activity useless. In a real app, core permissions would
            // typically be best requested during a welcome-screen flow.

            // Additionally, it is important to remember that a permission might have been
            // rejected without asking the img_user for permission (device policy or "Never ask
            // again" prompts). Therefore, a img_user interface affordance is typically implemented
            // when permissions are denied. Otherwise, your app could appear unresponsive to
            // touches or interactions which have required permissions.
            showSnackbar(R.string.permissionDenied,
                R.string.settings, new View.OnClickListener() 
                    @Override
                    public void onClick(View view) 
                        // Build intent that displays the App settings screen.
                        Intent intent = new Intent();
                        intent.setAction(
                                Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                        Uri uri = Uri.fromParts("package",
                                BuildConfig.APPLICATION_ID, null);
                        intent.setData(uri);
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        startActivity(intent);
                    
                );
        
    


@Override
public void onDestroy() 


    //Stop location sharing service to app server.........

    stopService(new Intent(this, LocationServicesForLocationUpdates.class));
    mAlreadyStartedService = false;
    //Ends................................................

    super.onDestroy();



如果您不理解我的问题,请随时提出任何问题,并告诉我解决问题的正确方法。我是安卓应用开发新手。

【问题讨论】:

你在哪里处理广播意图 - 在主要活动中 - 我没有看到它。接收活动应该在onCreate 中调用getIntent 在 onCreate 方法中有一个函数 LocalBroadcastManager.getInstance(this).registerReceiver ,在这里我得到了额外的意图。将经纬度分配给 MainActivity 的全局变量 【参考方案1】:

请在onMapReady() 中创建一个新的LatLng 位置并将其添加为MarkerOption

   @Override
   public void onMapReady(GoogleMap googleMap) 
       .......
       .......
    // make sure you  are getting your latitude and longitude string value
    mlattitude = Double.parseDouble(intent.getStringExtra(LocationServicesForLocationUpdates.EXTRA_LATITUDE));
    mlongitude = Double.parseDouble(intent.getStringExtra(LocationServicesForLocationUpdates.EXTRA_LONGITUDE));

 CameraPosition cameraPosition = new CameraPosition.Builder()
            .target(new LatLng(mLattitude,mlongitude)) // My position
            .zoom(14)           // Zoom Level
            .bearing(0)         // camera position, (0 north , 180 south )
            .tilt(90)           // Inclinaison de la camera
            .build();

    googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));

LatLng position = new LatLng(mlattitude,mlongitude);
googleMap.addMarker(new MarkerOptions().position(position)
            .title("my marker"));
   

编辑

不要忘记在您的onReceive() 方法中调用getMapAsync

    LocalBroadcastManager.getInstance(this).registerReceiver(
        new BroadcastReceiver() 
            @Override
            public void onReceive(Context context, Intent intent) 
                mlattitude = Double.parseDouble(intent.getStringExtra(LocationServicesForLocationUpdates.EXTRA_LATITUDE));
                mlongitude = Double.parseDouble(intent.getStringExtra(LocationServicesForLocationUpdates.EXTRA_LONGITUDE));

SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
        .findFragmentById(R.id.main_map);
mapFragment.getMapAsync(MainActivity.this);

                Log.d("latlng", "onReceive: " + mlongitude + mlattitude);
                if (mlattitude != null && mlongitude != null) 
                    mLatlngTxtVu.setText("Latitude : " + mlattitude + "Longitude: " + mlongitude);
                
            
        , new IntentFilter(LocationServicesForLocationUpdates.ACTION_LOCATION_BROADCAST)
);

);

【讨论】:

评论不用于扩展讨论;这个对话是moved to chat。【参考方案2】:

你可以这样做:

public class MapsMarkerActivity extends AppCompatActivity
    implements OnMapReadyCallback 
   // Include the OnCreate() method here too, as described above.
   @Override
   public void onMapReady(GoogleMap googleMap) 
       // Add a marker in Sydney, Australia,
       // and move the map's camera to the same location.
       LatLng sydney = new LatLng(-33.852, 151.211);
       googleMap.addMarker(new MarkerOptions().position(sydney)
            .title("Marker in Sydney"));
       googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
   

代码来自Google documentation page

【讨论】:

我也尝试了您的回答并阅读了完整的文档,但对我没有任何帮助。

以上是关于如何使用从服务中检索到的纬度和经度并在地图上显示它们?的主要内容,如果未能解决你的问题,请参考以下文章

如何从数据库中检索值

如何使用 JSON 纬度数组和 JSON 经度数组在 Google 地图上显示折线?

使用 Google 静态地图检索经度/纬度的问题

您如何单击地图并在表单中填充纬度和经度字段?

从用户地图上的 4 个角检索纬度和经度

如何将纬度/经度整合到数据集中并在地图上显示