Android显示当前位置的Google地图
在之前的Android Google地图教程中,我们只是显示了由MapsActivity.java类文件设置的默认坐标(位置)。
现在在这个教程中,我们将显示并在用户当前位置放置标记。要做到这一点,我们需要生成Google地图API密钥。生成Google地图API的过程在Android Google地图教程中有详述。
要显示用户当前位置,我们需要实现一些接口和回调方法。
Google地图中的回调方法
- OnMapRreadyCallback: 当该接口实例被设置在MapFragment对象上时,将调用此回调接口。 OnMapReadyCallback接口的onMapReady(GoogleMap)方法在地图准备好使用时被调用。在onMapReady(GoogleMap)方法中,我们可以添加标记,监听器和其他属性。
- LocationListener: 该接口用于接收设备位置发生更改时的通知。当位置发生变化时,会调用LocationListener的onLocationChanged(Location)方法。
- GoogleApiClient.ConnectionCallbacks: 此接口提供了onConnected(Bundle)和onConnectionSuspended(int)的回调方法,当设备连接和断开连接时会调用这些方法。
- GoogleApiClient.OnConnectionFailedListener: 此接口提供了onConnectionFailed(ConnectionResult)的回调方法,当连接设备与服务时发生错误时会调用该方法。
GoogleMap的 setMyLocationEnabled() 方法用于启用位置图层,允许设备与当前位置进行交互。
显示当前位置的Google地图示例
让我们看一个显示设备当前位置的Google地图示例。
activity_maps.xml
在activity_maps.xml文件中,在片段中添加SupportMapFragment。
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="example.com.mapexample.MapsActivity" />
build.gradel
在 build.gradel 文件中添加以下依赖项。
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.google.android.gms:play-services-maps:11.8.0'
compile 'com.google.android.gms:play-services-location:11.8.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}
MapsActivity.java
在MapsActivity.java文件中添加以下代码。
package example.com.mapexample;
import android.os.Build;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.location.LocationServices;
import android.location.Location;
import android.Manifest;
import android.content.pm.PackageManager;
import android.support.v4.content.ContextCompat;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback,
LocationListener,GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener{
private GoogleMap mMap;
Location mLastLocation;
Marker mCurrLocationMarker;
GoogleApiClient mGoogleApiClient;
LocationRequest mLocationRequest;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
}
}
else {
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
mGoogleApiClient.connect();
}
@Override
public void onConnected(Bundle bundle) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(1000);
mLocationRequest.setFastestInterval(1000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onLocationChanged(Location location) {
mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
//Place current location marker
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title("Current Position");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
mCurrLocationMarker = mMap.addMarker(markerOptions);
//move map camera
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(11));
//stop location updates
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
}
请求运行时权限
需要Android 6.0(Marshmallow)或更高版本的Android设备在运行时访问设备功能时需要一些权限。
在上面的MapsActivity.java文件中,我们添加了一个运行时权限 Manifest.permission.ACCESS_FINE_LOCATION 用于请求访问设备位置。运行时权限使用 checkSelfPermission() 方法进行检查,返回 PackageManager.PERMISSION_GRANTED 或 PackageManager.PERMISSION_DENIED 。如果权限被授予,则应用程序继续操作。
AndroidManifest.xml中需要的权限
在AndroidManifest.xml文件中添加以下用户权限。
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="example.com.mapexample">
<!--
The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
Google Maps Android API v2, but you must specify either coarse or fine
location permissions for the 'MyLocation' functionality.
-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!--
The API key for Google Maps-based APIs is defined as a string resource.
(See the file "res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to sign the APK.
You need a different API key for each encryption key, including the release key that is used to
sign the APK for publishing.
You can define the keys for the debug and release targets in src/debug/ and src/release/.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
<activity
android:name=".MapsActivity"
android:label="@string/title_activity_maps">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
输出